From 0c06516984ff1e45b8e69b2a044f6c85189dea88 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Thu, 28 May 2026 14:09:23 +0000 Subject: [PATCH 01/97] (qol): update release flake hash --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index f847bd6..3773515 100644 --- a/flake.nix +++ b/flake.nix @@ -6,8 +6,8 @@ outputs = {nixpkgs, ...}: let systems = ["x86_64-linux"]; forAllSystems = nixpkgs.lib.genAttrs systems; - version = "0.0.5"; - x86_64DebHash = "sha256-flC62rhhKyE/yRoNZRwXVHn/vwxE/Klxzj8uWhItDkY="; + version = "0.0.6"; + x86_64DebHash = "sha256-rNlyNZFgYVRvJzX1sBz/qLHUdZoyfvHl5xuwb2BtU48="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { packages = forAllSystems (system: let From 089e6c5b289888d6f3a5be1265328bbafc348fe5 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Fri, 29 May 2026 13:21:12 +0000 Subject: [PATCH 02/97] (qol): update release flake hash --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 3773515..41b621a 100644 --- a/flake.nix +++ b/flake.nix @@ -6,8 +6,8 @@ outputs = {nixpkgs, ...}: let systems = ["x86_64-linux"]; forAllSystems = nixpkgs.lib.genAttrs systems; - version = "0.0.6"; - x86_64DebHash = "sha256-rNlyNZFgYVRvJzX1sBz/qLHUdZoyfvHl5xuwb2BtU48="; + version = "0.0.7"; + x86_64DebHash = "sha256-gRkUEx1T7mrCgFEVp0X/ZiaGrKWzO+cCvv33DKCkB+o="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { packages = forAllSystems (system: let From abc0cceb56d96ce0f96dbf91cab710a8d61d47a0 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Wed, 3 Jun 2026 07:26:40 +0000 Subject: [PATCH 03/97] (qol): update release flake hash --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 41b621a..c1ae625 100644 --- a/flake.nix +++ b/flake.nix @@ -6,8 +6,8 @@ outputs = {nixpkgs, ...}: let systems = ["x86_64-linux"]; forAllSystems = nixpkgs.lib.genAttrs systems; - version = "0.0.7"; - x86_64DebHash = "sha256-gRkUEx1T7mrCgFEVp0X/ZiaGrKWzO+cCvv33DKCkB+o="; + version = "0.0.8"; + x86_64DebHash = "sha256-xC8YHVk+JpeMvXHB1dZihYLFyzFDXne4bkV6TZiOFrE="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { packages = forAllSystems (system: let From d545b91844fc49f85d20dba48cc3b46abb8a4ac5 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Tue, 9 Jun 2026 14:39:00 +0000 Subject: [PATCH 04/97] (qol): update release flake hash --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index c1ae625..b70fd6b 100644 --- a/flake.nix +++ b/flake.nix @@ -6,8 +6,8 @@ outputs = {nixpkgs, ...}: let systems = ["x86_64-linux"]; forAllSystems = nixpkgs.lib.genAttrs systems; - version = "0.0.8"; - x86_64DebHash = "sha256-xC8YHVk+JpeMvXHB1dZihYLFyzFDXne4bkV6TZiOFrE="; + version = "0.0.9"; + x86_64DebHash = "sha256-8rVb12SGGSac6l1NVPGyRLsAKAGDAOJVUwG8l+hoRCU="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { packages = forAllSystems (system: let From 4a23f8455ff20b4ebb7122b3d1b77adfc0aeef8a Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Tue, 16 Jun 2026 10:07:07 +0000 Subject: [PATCH 05/97] (qol): update release flake hash --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index cefe9d2..7d1d820 100644 --- a/flake.nix +++ b/flake.nix @@ -6,8 +6,8 @@ outputs = {nixpkgs, ...}: let systems = ["x86_64-linux"]; forAllSystems = nixpkgs.lib.genAttrs systems; - version = "0.0.9"; - x86_64DebHash = "sha256-8rVb12SGGSac6l1NVPGyRLsAKAGDAOJVUwG8l+hoRCU="; + version = "0.0.10"; + x86_64DebHash = "sha256-VVKkZ9yQ7BoLnYnCf5OSHcrakoBNfUx/uWxBmm3gBZE="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { packages = forAllSystems (system: let From 41bea6b107510eb90998e3d4f134af9d20cad69f Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Tue, 21 Jul 2026 09:19:47 +0000 Subject: [PATCH 06/97] (qol): update release flake hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 11a53a2..7945133 100644 --- a/flake.nix +++ b/flake.nix @@ -15,7 +15,7 @@ systems = ["x86_64-linux"]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.10"; - x86_64DebHash = "sha256-VVKkZ9yQ7BoLnYnCf5OSHcrakoBNfUx/uWxBmm3gBZE="; + x86_64DebHash = "sha256-9s47HyPJf/6yA6XGgKBJ+60gTXLTV/jvE2tS/Fth8zA="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { packages = forAllSystems (system: let From bf17f59a950ea746dfb3ef5cedfd178d1adbf6f8 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Tue, 21 Jul 2026 10:17:27 +0000 Subject: [PATCH 07/97] (qol): update release flake hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 46b11fd..10e384f 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.10"; - x86_64DebHash = "sha256-VVKkZ9yQ7BoLnYnCf5OSHcrakoBNfUx/uWxBmm3gBZE="; + x86_64DebHash = "sha256-TK7XmPWFbAVwlrE8hX8x+QsGFa0FTH9Mctmxu9JsHb4="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From cdc8d315053b4e7a3eb75b6bc939457b715748f7 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Sat, 1 Aug 2026 00:28:26 +0000 Subject: [PATCH 08/97] (qol): update release flake hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 5c15434..5b13c84 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.10"; - x86_64DebHash = "sha256-TK7XmPWFbAVwlrE8hX8x+QsGFa0FTH9Mctmxu9JsHb4="; + x86_64DebHash = "sha256-3CbaZnUT+hS6ClG5US6ZS7iy6kA82YlX/sJI3qFA81U="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From c1b10ef737ee6b85e0df503a341c5be7c5761376 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Wed, 5 Aug 2026 20:14:58 +0200 Subject: [PATCH 09/97] Add renovate.json --- renovate.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..7190a60 --- /dev/null +++ b/renovate.json @@ -0,0 +1,3 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json" +} From 329a35bcfbecd00237a04a3af22838d9bd2b82f2 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Wed, 5 Aug 2026 18:45:31 +0000 Subject: [PATCH 10/97] (qol): update release flake hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 5b13c84..6910d4a 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.10"; - x86_64DebHash = "sha256-3CbaZnUT+hS6ClG5US6ZS7iy6kA82YlX/sJI3qFA81U="; + x86_64DebHash = "sha256-R7ufXBPL2+jsgtbcIjPg55RU6m39odaC5IeLI1nYU48="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From 4c2b0e4c99202eff7faab0ea437a419ddf71149f Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Wed, 5 Aug 2026 18:45:33 +0000 Subject: [PATCH 11/97] (qol): update release flake hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 1965277..2d34e76 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.10"; - x86_64DebHash = "sha256-3CbaZnUT+hS6ClG5US6ZS7iy6kA82YlX/sJI3qFA81U="; + x86_64DebHash = "sha256-R7ufXBPL2+jsgtbcIjPg55RU6m39odaC5IeLI1nYU48="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From 07e31d1ad6e4a8dde08e33b4250096c315c4c5e5 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Wed, 5 Aug 2026 21:00:39 +0200 Subject: [PATCH 12/97] chore(deps): update dependency @base-ui/utils to v0.3.2 --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index d95d914..1f313f6 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@base-ui/react": "^1.0.0", - "@base-ui/utils": "0.3.1", + "@base-ui/utils": "0.3.2", "@babel/runtime": "^7.29.2", "@fontsource-variable/inter": "^5.2.8", "@fontsource-variable/public-sans": "^5.2.7", From 43fd0beb8eb45f2acd6e9207cf7e9f4b700b9679 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Wed, 5 Aug 2026 21:00:47 +0200 Subject: [PATCH 13/97] chore(deps): update dependency @radix-ui/react-use-effect-event to ^0.0.5 --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index d95d914..773e403 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -35,7 +35,7 @@ "@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-use-callback-ref": "^1.1.1", "@radix-ui/react-use-controllable-state": "^1.2.3", - "@radix-ui/react-use-effect-event": "^0.0.2", + "@radix-ui/react-use-effect-event": "^0.0.5", "@radix-ui/react-use-layout-effect": "^1.1.0", "@reduxjs/toolkit": "^2.0.0", "@tailwindcss/vite": "^4.2.4", From 4a841de073682a84874e6f2af6e7956df41ac9e0 Mon Sep 17 00:00:00 2001 From: Alois Date: Wed, 5 Aug 2026 21:41:55 +0200 Subject: [PATCH 14/97] (feat): improved mobile notifications (feat): add lint rules (feat): improve markdown inline code box --- apps/electron/build/icons/icon.icns | Bin 257363 -> 257363 bytes apps/tauri/monochrome_cropped.png | Bin 0 -> 2833 bytes .../android/app/src/main/AndroidManifest.xml | 1 + .../java/net/tensamin/client/MainActivity.kt | 4 +- .../tensamin/client/MtpForegroundService.kt | 14 +- .../net/tensamin/client/NativeMtpBridge.kt | 41 +++- .../res/drawable/ic_notification_small.png | Bin 0 -> 8525 bytes apps/tauri/src-tauri/icons/icon.icns | Bin 257363 -> 257363 bytes apps/tauri/src-tauri/src/lib.rs | 22 +- apps/tauri/src-tauri/src/mtp_backend.rs | 97 +++++++- apps/tauri/src/deeplinkHandler.tsx | 8 +- apps/web/src/index.tsx | 33 ++- eslint.config.ts | 3 + packages/call/src/mediaShare/controller.ts | 30 +-- packages/call/src/mediaShare/tauri.ts | 42 ++-- packages/call/src/speakingIndicator.ts | 21 +- packages/call/src/speakingState.ts | 6 +- packages/call/src/store.tsx | 83 +++---- packages/chat/src/components/gifPicker.tsx | 50 ++-- packages/chat/src/components/input.tsx | 7 + packages/chat/src/context.tsx | 4 +- packages/chat/src/screen.tsx | 14 +- packages/markdown/src/emojiData.ts | 4 +- packages/markdown/src/input.tsx | 18 +- packages/markdown/src/markdown.tsx | 226 +++++++++++++----- packages/mtp/src/context.tsx | 21 +- packages/notifications/src/context.tsx | 27 ++- packages/onboarding/src/index.tsx | 4 +- packages/onboarding/src/pages/legal.tsx | 4 +- packages/settings/src/components.tsx | 8 +- packages/shared/src/data.ts | 40 ++-- packages/shared/src/desktopMedia.tsx | 10 +- packages/shared/src/settings.ts | 12 +- utils/eslint-rules/index.ts | 208 ++++++++++++++++ utils/scripts/lint-packages.ts | 2 +- 35 files changed, 777 insertions(+), 287 deletions(-) create mode 100644 apps/tauri/monochrome_cropped.png create mode 100644 apps/tauri/src-tauri/gen/android/app/src/main/res/drawable/ic_notification_small.png diff --git a/apps/electron/build/icons/icon.icns b/apps/electron/build/icons/icon.icns index 7f3b5918284138bd07f143d54075ac99c7672c68..a7f0a1e940bbdd0f4c8b453dc3ff837603c4dc08 100644 GIT binary patch delta 72 zcmcb7i~sU1evZuKykZ9Cx53*TLm7W9+Fa->#@TN9gK@j%52ii+tmX_1W)CNSG!x#a eeB5mNsr$^GyqjN|wTo^4($0J>d~aj`h(_L=XPcKu_?Og6CGp5Vp& cc~P_Yn(g9i829#XKQfK!YWVieMNFN%06SkE!2kdN diff --git a/apps/tauri/monochrome_cropped.png b/apps/tauri/monochrome_cropped.png new file mode 100644 index 0000000000000000000000000000000000000000..424ebd1faf1814abfeeb3a169ba1fd7e8b2ae871 GIT binary patch literal 2833 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 = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { @@ -44,6 +48,7 @@ class MtpForegroundService : Service() { try { NativeMtpBridge.nativeAttach(applicationContext) NativeMtpBridge.nativeStart(config) + started = true NativeMtpBridge.log(2, "Started MTP foreground service") } catch (error: Throwable) { NativeMtpBridge.log(0, "Failed to start MTP foreground service", error) @@ -52,6 +57,13 @@ class MtpForegroundService : Service() { return START_STICKY } + override fun onTaskRemoved(rootIntent: Intent?) { + if (MtpSecureStore.isEnabled(this) && MtpSecureStore.hasConfig(this)) { + startService(Intent(this, MtpForegroundService::class.java)) + } + super.onTaskRemoved(rootIntent) + } + override fun onDestroy() { if (!MtpSecureStore.isEnabled(this)) NativeMtpBridge.nativeStop() super.onDestroy() @@ -95,7 +107,7 @@ class MtpForegroundService : Service() { ) return NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(android.R.drawable.stat_notify_sync) - .setContentTitle("Tensamin background connection") + .setContentTitle("Tensamin") .setContentText(status) .setContentIntent(openIntent) .setOngoing(true) diff --git a/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/NativeMtpBridge.kt b/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/NativeMtpBridge.kt index 996daf0..ba9422d 100644 --- a/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/NativeMtpBridge.kt +++ b/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/NativeMtpBridge.kt @@ -6,6 +6,7 @@ import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import android.content.Intent +import android.graphics.BitmapFactory import android.net.Uri import android.os.Build import android.os.PowerManager @@ -13,7 +14,12 @@ import android.provider.Settings import android.util.Log import androidx.annotation.Keep import androidx.core.app.NotificationCompat +import androidx.core.app.Person +import androidx.core.content.LocusIdCompat import androidx.core.content.ContextCompat +import androidx.core.content.pm.ShortcutInfoCompat +import androidx.core.content.pm.ShortcutManagerCompat +import androidx.core.graphics.drawable.IconCompat @Keep object NativeMtpBridge { @@ -85,6 +91,7 @@ object NativeMtpBridge { senderId: Long, sender: String, body: String, + avatar: ByteArray, ) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.getSystemService(NotificationManager::class.java).createNotificationChannel( @@ -107,11 +114,36 @@ object NativeMtpBridge { openIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, ) + val avatarBitmap = avatar.takeIf { it.isNotEmpty() }?.let { + BitmapFactory.decodeByteArray(it, 0, it.size) + } + val avatarIcon = avatarBitmap?.let(IconCompat::createWithAdaptiveBitmap) + val person = Person.Builder() + .setName(sender) + .setKey(senderId.toString()) + .setIcon(avatarIcon) + .build() + val shortcutId = "chat-$senderId" + val shortcut = ShortcutInfoCompat.Builder(context, shortcutId) + .setShortLabel(sender) + .setLongLived(true) + .setPerson(person) + .setIntent(openIntent) + .apply { if (avatarIcon != null) setIcon(avatarIcon) } + .build() + ShortcutManagerCompat.pushDynamicShortcut(context, shortcut) + + val style = NotificationCompat.MessagingStyle( + Person.Builder().setName("You").build(), + ).addMessage(body, System.currentTimeMillis(), person) val notification = NotificationCompat.Builder(context, MESSAGE_CHANNEL) - .setSmallIcon(android.R.drawable.sym_action_chat) + .setSmallIcon(R.drawable.ic_notification_small) .setContentTitle(sender) .setContentText(body) - .setStyle(NotificationCompat.BigTextStyle().bigText(body)) + .setStyle(style) + .setShortcutId(shortcutId) + .setLocusId(LocusIdCompat(shortcutId)) + .setLargeIcon(avatarBitmap) .setCategory(Notification.CATEGORY_MESSAGE) .setAutoCancel(true) .setContentIntent(pendingIntent) @@ -121,4 +153,9 @@ object NativeMtpBridge { .notify(senderId.hashCode(), notification) } + fun cancelMessageNotification(context: Context, senderId: Long) { + context.getSystemService(NotificationManager::class.java) + .cancel(senderId.hashCode()) + } + } diff --git a/apps/tauri/src-tauri/gen/android/app/src/main/res/drawable/ic_notification_small.png b/apps/tauri/src-tauri/gen/android/app/src/main/res/drawable/ic_notification_small.png new file mode 100644 index 0000000000000000000000000000000000000000..bec055d05956f03db912fd7bff42974e166b3225 GIT binary patch literal 8525 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 literal 0 HcmV?d00001 diff --git a/apps/tauri/src-tauri/icons/icon.icns b/apps/tauri/src-tauri/icons/icon.icns index 7f3b5918284138bd07f143d54075ac99c7672c68..a7f0a1e940bbdd0f4c8b453dc3ff837603c4dc08 100644 GIT binary patch delta 72 zcmcb7i~sU1evZuKykZ9Cx53*TLm7W9+Fa->#@TN9gK@j%52ii+tmX_1W)CNSG!x#a eeB5mNsr$^GyqjN|wTo^4($0J>d~aj`h(_L=XPcKu_?Og6CGp5Vp& cc~P_Yn(g9i829#XKQfK!YWVieMNFN%06SkE!2kdN diff --git a/apps/tauri/src-tauri/src/lib.rs b/apps/tauri/src-tauri/src/lib.rs index 5d49556..8131b57 100644 --- a/apps/tauri/src-tauri/src/lib.rs +++ b/apps/tauri/src-tauri/src/lib.rs @@ -17,7 +17,7 @@ pub fn run() { #[cfg(any(target_os = "ios", target_os = "android"))] let builder = builder.plugin(tauri_plugin_barcode_scanner::init()); - if let Err(error) = builder + let app = builder .invoke_handler(tauri::generate_handler![ mtp_backend::mtp_request, mtp_backend::mtp_status, @@ -26,6 +26,7 @@ pub fn run() { mtp_backend::mtp_load_keyring, mtp_backend::mtp_set_enabled, mtp_backend::mtp_set_ui_visible, + mtp_backend::mtp_post_message_notification, mtp_backend::mtp_is_ignoring_battery_optimizations, mtp_backend::mtp_request_battery_exemption, ]) @@ -45,9 +46,18 @@ pub fn run() { } Ok(()) }) - .run(tauri::generate_context!()) - { - eprintln!("error while running tauri application: {error}"); - panic!("error while running tauri application: {error}"); - } + .build(tauri::generate_context!()) + .expect("error while building tauri application"); + + app.run(|_app, event| { + #[cfg(target_os = "android")] + if let tauri::RunEvent::ExitRequested { + api, code: None, .. + } = event + { + if mtp_backend::manager().is_enabled() { + api.prevent_exit(); + } + } + }); } diff --git a/apps/tauri/src-tauri/src/mtp_backend.rs b/apps/tauri/src-tauri/src/mtp_backend.rs index 8cbfb8d..7c65b03 100644 --- a/apps/tauri/src-tauri/src/mtp_backend.rs +++ b/apps/tauri/src-tauri/src/mtp_backend.rs @@ -56,7 +56,7 @@ Zwkt6K2EOMmh1nvEzl83eMLYcod4GCl3b0J1Nn0CMBNYmEQJb4CEG5WoOe7aRn/L\n\ VKu6saHmHEynI7ysIPd8zQsK1HdmhlHKlw9Z5GpGvA==\n\ -----END CERTIFICATE-----\n"; -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] #[serde(rename_all = "camelCase")] pub struct MtpConfig { pub user_id: u64, @@ -135,6 +135,11 @@ impl MtpManager { pub fn configure_and_start(&'static self, config: MtpConfig) { let _guard = self.start_lock.lock().expect("start lock poisoned"); + if self.enabled.load(Ordering::SeqCst) + && self.config.read().expect("config lock poisoned").as_ref() == Some(&config) + { + return; + } *self.config.write().expect("config lock poisoned") = Some(config); self.enabled.store(true, Ordering::SeqCst); let generation = self.generation.fetch_add(1, Ordering::SeqCst) + 1; @@ -182,6 +187,10 @@ impl MtpManager { self.ui_visible.store(visible, Ordering::SeqCst); } + pub fn is_enabled(&self) -> bool { + self.enabled.load(Ordering::SeqCst) + } + pub fn snapshot(&self) -> MtpSnapshot { self.snapshot .read() @@ -446,6 +455,19 @@ async fn handle_push(generation: u64, connection: Arc, frame: Com message, }); } + if frame.is_type(CommunicationType::MessageState) + && frame.get_str(DataType::MessageState) == Some("read") + { + if let Some(partner_id) = frame + .get_data(DataType::ChatPartnerId) + .as_number() + .and_then(|value| u64::try_from(value).ok()) + { + if let Err(error) = android_cancel_notification(partner_id) { + eprintln!("failed to clear read message notification: {error}"); + } + } + } if frame.is_type(CommunicationType::MessageLive) && !manager.ui_visible.load(Ordering::SeqCst) { if let Err(error) = notify_message(connection, &frame).await { eprintln!("failed to create background message notification: {error}"); @@ -533,7 +555,15 @@ async fn notify_message( .or_else(|| user.get_str(DataType::Username)) .map(str::to_owned) .unwrap_or_else(|| format!("User {sender_id}")); - android_notify(sender_id, &sender, &String::from_utf8_lossy(&plaintext)); + let avatar = user + .get_str(DataType::Avatar) + .and_then(|avatar| decode_browser_base64(avatar).ok()); + android_notify( + sender_id, + &sender, + &String::from_utf8_lossy(&plaintext), + avatar.as_deref(), + )?; Ok(()) } @@ -834,6 +864,26 @@ pub fn mtp_set_ui_visible(visible: bool) { manager().set_ui_visible(visible); } +#[tauri::command] +pub fn mtp_post_message_notification( + sender_id: u64, + sender: String, + body: String, + avatar: Option, +) -> Result { + #[cfg(target_os = "android")] + { + let avatar = avatar.as_deref().map(decode_browser_base64).transpose()?; + android_notify(sender_id, &sender, &body, avatar.as_deref())?; + Ok(true) + } + #[cfg(not(target_os = "android"))] + { + let _ = (sender_id, sender, body, avatar); + Ok(false) + } +} + #[cfg(not(target_os = "android"))] fn android_store_config(_: &str) -> Result<(), String> { Ok(()) @@ -853,7 +903,13 @@ fn android_set_enabled(_: bool) -> Result<(), String> { #[cfg(not(target_os = "android"))] fn android_status(_: &str) {} #[cfg(not(target_os = "android"))] -fn android_notify(_: u64, _: &str, _: &str) {} +fn android_notify(_: u64, _: &str, _: &str, _: Option<&[u8]>) -> Result<(), String> { + Ok(()) +} +#[cfg(not(target_os = "android"))] +fn android_cancel_notification(_: u64) -> Result<(), String> { + Ok(()) +} #[cfg(not(target_os = "android"))] fn android_is_ignoring_battery_optimizations() -> Result { Ok(true) @@ -974,24 +1030,49 @@ mod android { }); } - pub fn notify(sender_id: u64, sender: &str, body: &str) { - let _ = with_env(|env, host| { + pub fn notify( + sender_id: u64, + sender: &str, + body: &str, + avatar: Option<&[u8]>, + ) -> Result<(), String> { + with_env(|env, host| { let sender = env.new_string(sender).map_err(|e| e.to_string())?; let body = env.new_string(body).map_err(|e| e.to_string())?; + let avatar = env + .byte_array_from_slice(avatar.unwrap_or_default()) + .map_err(|e| e.to_string())?; env.call_method( host.bridge.as_obj(), "postMessageNotification", - "(Landroid/content/Context;JLjava/lang/String;Ljava/lang/String;)V", + "(Landroid/content/Context;JLjava/lang/String;Ljava/lang/String;[B)V", &[ JValue::Object(host.context.as_obj()), JValue::Long(sender_id as i64), JValue::Object(&sender), JValue::Object(&body), + JValue::Object(&avatar), ], ) .map_err(|e| e.to_string())?; Ok(()) - }); + }) + } + + pub fn cancel_notification(sender_id: u64) -> Result<(), String> { + with_env(|env, host| { + env.call_method( + host.bridge.as_obj(), + "cancelMessageNotification", + "(Landroid/content/Context;J)V", + &[ + JValue::Object(host.context.as_obj()), + JValue::Long(sender_id as i64), + ], + ) + .map_err(|e| e.to_string())?; + Ok(()) + }) } pub fn is_ignoring_battery_optimizations() -> Result { @@ -1084,7 +1165,7 @@ mod android { #[cfg(target_os = "android")] use android::{ - has_config as android_has_config, + cancel_notification as android_cancel_notification, has_config as android_has_config, is_ignoring_battery_optimizations as android_is_ignoring_battery_optimizations, notify as android_notify, request_battery_exemption as android_request_battery_exemption, set_enabled as android_set_enabled, status as android_status, diff --git a/apps/tauri/src/deeplinkHandler.tsx b/apps/tauri/src/deeplinkHandler.tsx index 2094b73..dcbb5c7 100644 --- a/apps/tauri/src/deeplinkHandler.tsx +++ b/apps/tauri/src/deeplinkHandler.tsx @@ -9,11 +9,11 @@ import { getCurrent, onOpenUrl } from "@tauri-apps/plugin-deep-link"; import { isTauri } from "@tauri-apps/api/core"; import { useIsMobile } from "@methanium/ui"; -type DeeplinkContextValue = { - deeplinks: readonly string[]; -}; -export const deeplinkContext = createContext( + +export const deeplinkContext = createContext<{ + deeplinks: readonly string[]; +} | undefined>( undefined, ); diff --git a/apps/web/src/index.tsx b/apps/web/src/index.tsx index 6fbeae6..60d5ac9 100644 --- a/apps/web/src/index.tsx +++ b/apps/web/src/index.tsx @@ -27,7 +27,7 @@ import { useCall, useInitializeCall } from "@tensamin/call/store"; import { useIsSpeaking } from "@tensamin/call/speakingState"; import { Provider as MTPProvider } from "@tensamin/mtp"; import UserProvider from "@tensamin/user/context"; -import DeeplinkContext from "@tensamin/tauri/deeplinkHandler"; +import DeeplinkContext, { useDeeplinks } from "@tensamin/tauri/deeplinkHandler"; import NotificationsProvider from "@tensamin/notifications/context"; import TAuthWrapper from "@tensamin/tauth/context"; @@ -288,6 +288,7 @@ function AppShell() { + @@ -309,6 +310,36 @@ function AppShell() { ); } +function DeeplinkNavigator() { + const { deeplinks } = useDeeplinks(); + const navigate = useNavigate(); + const handledCount = useRef(0); + + useEffect(() => { + const links = deeplinks.slice(handledCount.current); + handledCount.current = deeplinks.length; + + for (const link of links) { + try { + const url = new URL(link); + const id = Number(url.searchParams.get("id")); + if ( + url.protocol === "tensamin:" && + url.hostname === "chat" && + Number.isSafeInteger(id) && + id > 0 + ) { + void navigate({ to: "/chat", search: { id } }); + } + } catch { + // Ignore malformed URLs delivered by the platform. + } + } + }, [deeplinks, navigate]); + + return null; +} + function createCallTrayIcon(color: string, speaking: boolean) { const canvas = document.createElement("canvas"); canvas.width = 32; diff --git a/eslint.config.ts b/eslint.config.ts index df086d6..f9bc102 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -6,6 +6,7 @@ import * as tsParser from "@typescript-eslint/parser"; import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { + inlineSingleUseDeclarations, noReactNamespaceImport, noWindowLocationReload, } from "./utils/eslint-rules/index.js"; @@ -34,6 +35,7 @@ export default [ "react-hooks": reactHooks, tensamin: { rules: { + "inline-single-use-declarations": inlineSingleUseDeclarations, "no-react-namespace-import": noReactNamespaceImport, "no-window-location-reload": noWindowLocationReload, }, @@ -42,6 +44,7 @@ export default [ rules: { ...reactHooks.configs.recommended.rules, "react-hooks/set-state-in-effect": "off", + "tensamin/inline-single-use-declarations": "error", "tensamin/no-react-namespace-import": "error", "tensamin/no-window-location-reload": "error", }, diff --git a/packages/call/src/mediaShare/controller.ts b/packages/call/src/mediaShare/controller.ts index a2fde87..f123834 100644 --- a/packages/call/src/mediaShare/controller.ts +++ b/packages/call/src/mediaShare/controller.ts @@ -17,22 +17,6 @@ type MediaShareStoreState = { cameraSession: LocalMediaShareSession | null; }; -type MediaShareStoreSetState = ( - updater: - | Partial - | ((state: MediaShareStoreState) => Partial), -) => void; - -type MediaShareControllerOptions = { - room: Room; - getState: () => MediaShareStoreState; - setState: MediaShareStoreSetState; - getLocalParticipantId: () => number | null; - startWatching: (participantId: number) => void; - stopWatching: (participantId: number) => void; - syncParticipantState: () => void; -}; - export function createMediaShareController({ room, getState, @@ -41,7 +25,19 @@ export function createMediaShareController({ startWatching, stopWatching, syncParticipantState, -}: MediaShareControllerOptions) { +}: { + room: Room; + getState: () => MediaShareStoreState; + setState: ( + updater: + | Partial + | ((state: MediaShareStoreState) => Partial), + ) => void; + getLocalParticipantId: () => number | null; + startWatching: (participantId: number) => void; + stopWatching: (participantId: number) => void; + syncParticipantState: () => void; +}) { function getSession(kind: MediaShareKind) { return kind === "screen" ? getState().screenShareSession diff --git a/packages/call/src/mediaShare/tauri.ts b/packages/call/src/mediaShare/tauri.ts index e88034e..7263599 100644 --- a/packages/call/src/mediaShare/tauri.ts +++ b/packages/call/src/mediaShare/tauri.ts @@ -8,32 +8,16 @@ import type { MediaShareSource, } from "./types"; -type MobileMediaApi = { - startScreenShare: (includeAudio: boolean) => void; - stopScreenShare: () => void; - requestCameraPermission: () => void; -}; - declare global { interface Window { - tensaminMobileMedia?: MobileMediaApi; + tensaminMobileMedia?: { + startScreenShare: (includeAudio: boolean) => void; + stopScreenShare: () => void; + requestCameraPermission: () => void; + }; } } -type FrameDetail = { - data: string; - mimeType: string; - width: number; - height: number; -}; - -type AudioDetail = { - data: string; - sampleRate: number; - channelCount: number; - encoding: "pcm16le"; -}; - function eventDetail(event: Event): T { return (event as CustomEvent).detail; } @@ -164,7 +148,12 @@ async function startMobileScreen( }; const onFrame = (event: Event) => { - const detail = eventDetail(event); + const detail = eventDetail<{ + data: string; + mimeType: string; + width: number; + height: number; + }>(event); const image = new Image(); image.onload = () => { if (canvas.width !== detail.width || canvas.height !== detail.height) { @@ -179,7 +168,14 @@ async function startMobileScreen( }; const onAudio = (event: Event) => { - const bytes = decodeBase64(eventDetail(event).data); + const bytes = decodeBase64( + eventDetail<{ + data: string; + sampleRate: number; + channelCount: number; + encoding: "pcm16le"; + }>(event).data, + ); const samples = new Int16Array( bytes.buffer, bytes.byteOffset, diff --git a/packages/call/src/speakingIndicator.ts b/packages/call/src/speakingIndicator.ts index a887516..94ff030 100644 --- a/packages/call/src/speakingIndicator.ts +++ b/packages/call/src/speakingIndicator.ts @@ -10,18 +10,19 @@ const SPEAKING_HANGTIME_MS = 500; const ANALYSIS_INTERVAL_MS = 30; const FFT_SIZE = 256; -type AnalyserEntry = { - source: MediaStreamAudioSourceNode; - analyser: AnalyserNode; - track: MediaStreamTrack; - originalTrack?: MediaStreamTrack; - lastSpeakingTime: number; - isSpeaking: boolean; -}; - class SpeakingDetector { private audioContext: AudioContext | null = null; - private entries = new Map(); + private entries = new Map< + number, + { + source: MediaStreamAudioSourceNode; + analyser: AnalyserNode; + track: MediaStreamTrack; + originalTrack?: MediaStreamTrack; + lastSpeakingTime: number; + isSpeaking: boolean; + } + >(); private intervalId: ReturnType | null = null; private deaf = false; private gateThresholdStart = -50; diff --git a/packages/call/src/speakingState.ts b/packages/call/src/speakingState.ts index b689bf5..c4f5198 100644 --- a/packages/call/src/speakingState.ts +++ b/packages/call/src/speakingState.ts @@ -1,12 +1,10 @@ import { create } from "zustand"; -type SpeakingState = { +const useSpeakingState = create<{ speakingParticipantIds: Set; lastSpeakingParticipantId: number | null; micGated: boolean; -}; - -const useSpeakingState = create(() => ({ +}>(() => ({ speakingParticipantIds: new Set(), lastSpeakingParticipantId: null, micGated: false, diff --git a/packages/call/src/store.tsx b/packages/call/src/store.tsx index 5def2b6..687919b 100644 --- a/packages/call/src/store.tsx +++ b/packages/call/src/store.tsx @@ -51,7 +51,6 @@ setLogExtension( getLogger("tensamin"), ); -type CallState = "closed" | "closing" | "connecting" | "open" | "encrypting"; type CallView = "preview" | "focused" | "grid"; type ProtocolCallSecret = NonNullable< z.infer["CallSecret"] @@ -63,18 +62,9 @@ type WrappedCallSecret = { kemCiphertext: Uint8Array; wrappingScheme: string; }; -type IncomingCallInvite = { - callId: string; - callSecret: WrappedCallSecret; - senderId: number; -}; type CurrentCallData = (z.infer & { exists: boolean }) | null; -type NavigateFn = (options: { - to: string; - search?: Record; -}) => Promise; type SendFn = ( type: string, data: Record, @@ -84,44 +74,15 @@ type GetUserFn = (userId: number) => Promise<{ PublicKey: string }>; type RemoteVideoTrackSelector = Track.Kind | Track.Source; type Runtime = { - navigate: NavigateFn; + navigate: (options: { + to: string; + search?: Record; + }) => Promise; send: SendFn; load: LoadFn; getUser: GetUserFn; }; -type CallStore = { - state: CallState; - view: CallView; - invitedUserId: number | null; - callId: string | null; - incomingCallInvite: IncomingCallInvite | null; - callSecret: string | null; - livekitToken: string | null; - currentCallData: CurrentCallData; - deaf: boolean; - micEnabled: boolean; - cameraEnabled: boolean; - screenShareEnabled: boolean; - screenShareSession: LocalMediaShareSession | null; - cameraSession: LocalMediaShareSession | null; - disabledCameraParticipantIds: number[]; - focusedParticipantId: number | null; - focusedParticipantType: "user" | "stream" | null; - usersInFocusedViewHidden: boolean; - watchedStreamParticipantIds: number[]; - pendingWatchedParticipantIds: number[]; - activeScreenShareParticipantIds: number[]; - isEncrypted: boolean; - ownCallSecretInvitePending: boolean; - callIsFullscreen: boolean; - callIsPopout: boolean; - layoutVersion: number; - screenRef: React.RefObject | null; - runtime: Runtime | null; - lastFocusedParticipantId: number | null; -}; - let _keyProvider: ExternalE2EEKeyProvider | null = null; let _e2eeWorker: Worker | null = null; let _room: Room | null = null; @@ -1195,7 +1156,41 @@ async function ensureNoiseFilter( } } -export const useCall = create(() => ({ +export const useCall = create<{ + state: "closed" | "closing" | "connecting" | "open" | "encrypting"; + view: CallView; + invitedUserId: number | null; + callId: string | null; + incomingCallInvite: { + callId: string; + callSecret: WrappedCallSecret; + senderId: number; + } | null; + callSecret: string | null; + livekitToken: string | null; + currentCallData: CurrentCallData; + deaf: boolean; + micEnabled: boolean; + cameraEnabled: boolean; + screenShareEnabled: boolean; + screenShareSession: LocalMediaShareSession | null; + cameraSession: LocalMediaShareSession | null; + disabledCameraParticipantIds: number[]; + focusedParticipantId: number | null; + focusedParticipantType: "user" | "stream" | null; + usersInFocusedViewHidden: boolean; + watchedStreamParticipantIds: number[]; + pendingWatchedParticipantIds: number[]; + activeScreenShareParticipantIds: number[]; + isEncrypted: boolean; + ownCallSecretInvitePending: boolean; + callIsFullscreen: boolean; + callIsPopout: boolean; + layoutVersion: number; + screenRef: React.RefObject | null; + runtime: Runtime | null; + lastFocusedParticipantId: number | null; +}>(() => ({ state: "closed", view: "preview", invitedUserId: null, diff --git a/packages/chat/src/components/gifPicker.tsx b/packages/chat/src/components/gifPicker.tsx index fbec74b..e44742b 100644 --- a/packages/chat/src/components/gifPicker.tsx +++ b/packages/chat/src/components/gifPicker.tsx @@ -34,35 +34,25 @@ function getColumnCount(width: number, itemCount: number) { type KlipyKind = "gif" | "meme"; -type KlipyMediaFile = { - url?: string; - width?: number; - height?: number; -}; - -type KlipyMediaFormats = Record; - type KlipyItem = { id: number | string; title?: string; - file?: Record; + file?: Record< + string, + | Record< + string, + | { + url?: string; + width?: number; + height?: number; + } + | undefined + > + | undefined + >; blur_preview?: string; }; -type KlipyPage = { - items: KlipyItem[]; - currentPage: number; - hasNext: boolean; -}; - -type KlipyResponse = { - data?: { - data?: KlipyItem[]; - current_page?: number; - has_next?: boolean; - }; -}; - type PickerMedia = { key: React.Key; url: string; @@ -105,7 +95,11 @@ async function fetchKlipyPage({ kind: KlipyKind; page: number; search: string; -}): Promise { +}): Promise<{ + items: KlipyItem[]; + currentPage: number; + hasNext: boolean; +}> { const params = new URLSearchParams({ page: String(page), per_page: String(pageSize), @@ -128,7 +122,13 @@ async function fetchKlipyPage({ throw new Error(`Klipy request failed with status ${response.status}`); } - const body = (await response.json()) as KlipyResponse; + const body = (await response.json()) as { + data?: { + data?: KlipyItem[]; + current_page?: number; + has_next?: boolean; + }; + }; const data = body.data; return { diff --git a/packages/chat/src/components/input.tsx b/packages/chat/src/components/input.tsx index 5d6088a..e54235d 100644 --- a/packages/chat/src/components/input.tsx +++ b/packages/chat/src/components/input.tsx @@ -66,6 +66,13 @@ export default function InputComponent({ return () => cancelAnimationFrame(frame); }, [userId]); + useEffect(() => { + if (replyTo === undefined) return; + + const frame = requestAnimationFrame(() => composerRef.current?.focus()); + return () => cancelAnimationFrame(frame); + }, [replyTo]); + useEffect(() => { const focusComposerOnType = (event: KeyboardEvent) => { const composer = composerRef.current; diff --git a/packages/chat/src/context.tsx b/packages/chat/src/context.tsx index 78c1bb2..5b6e796 100644 --- a/packages/chat/src/context.tsx +++ b/packages/chat/src/context.tsx @@ -145,8 +145,6 @@ type SendMessageGet = ( data: { SendTime: number }, ) => Promise<{ data: RawMessage }>; -type GetChatSecret = (userId: number) => Promise; - type StoredDraftState = ChatDraft & { accountId: number; userId: number; @@ -204,7 +202,7 @@ export async function fetchReplyMessage({ ownId: number; chatUserId: number; send: SendMessageGet; - getChatSecret: GetChatSecret; + getChatSecret: (userId: number) => Promise; }) { const message = await getMessage({ sendTime: replyTo, diff --git a/packages/chat/src/screen.tsx b/packages/chat/src/screen.tsx index 8b3778e..0587d54 100644 --- a/packages/chat/src/screen.tsx +++ b/packages/chat/src/screen.tsx @@ -21,12 +21,6 @@ import { } from "./values"; import Wrapper from "@tensamin/user/wrapper"; -type MessageChunk = { - key: string; - messages: Array; - startIndex: number; -}; - function shouldFetchPreviousPage({ entry, hasNextPage, @@ -108,7 +102,11 @@ function buildMessageChunks( keyPrefix: string, startOffset = 0, ) { - const chunks: MessageChunk[] = []; + const chunks: { + key: string; + messages: Array; + startIndex: number; + }[] = []; for (let end = messages.length; end > 0; end -= MESSAGES_PER_VIRTUAL_ROW) { const start = Math.max(0, end - MESSAGES_PER_VIRTUAL_ROW); @@ -282,7 +280,7 @@ export default function Screen() { getItemKey, estimateSize, overscan: 2, - paddingStart: composerHeight + 8, + paddingStart: composerHeight + 20, }); const totalSize = virtualizer.getTotalSize(); const contentHeight = Math.max(totalSize, viewportHeight); diff --git a/packages/markdown/src/emojiData.ts b/packages/markdown/src/emojiData.ts index f1ed5ab..158b5b0 100644 --- a/packages/markdown/src/emojiData.ts +++ b/packages/markdown/src/emojiData.ts @@ -1,7 +1,5 @@ import shortcodeData from "emojibase-data/en/shortcodes/joypixels.json"; -type ShortcodeValue = string | string[]; - export type EmojiDefinition = { aliases: readonly string[]; hexcode: string; @@ -17,7 +15,7 @@ function normalizeName(value: string) { } export const emojis: readonly EmojiDefinition[] = Object.entries( - shortcodeData as Record, + shortcodeData as Record, ).map(([hexcode, value]) => { const aliases = Array.isArray(value) ? value : [value]; const name = aliases[0]; diff --git a/packages/markdown/src/input.tsx b/packages/markdown/src/input.tsx index 58ebe9f..e16c84d 100644 --- a/packages/markdown/src/input.tsx +++ b/packages/markdown/src/input.tsx @@ -76,10 +76,6 @@ export type InputProps = { onControllerChange?: (controller: InputController | null) => void; }; -type InputStyle = CSSProperties & { - "--tm-md-content-padding"?: string; -}; - function toCssLength(value: CSSProperties["padding"]): string | undefined { if (value === undefined) { return undefined; @@ -99,11 +95,6 @@ function toCssPadding( return `${toCssLength(vertical) ?? defaultVertical} ${toCssLength(horizontal) ?? defaultHorizontal}`; } -type TokenRange = { - from: number; - to: number; -}; - const hiddenTokenDecoration = Decoration.mark({ class: "tm-md-hidden-token" }); const strongDecoration = Decoration.mark({ class: "tm-md-strong" }); const emDecoration = Decoration.mark({ class: "tm-md-em" }); @@ -443,7 +434,9 @@ export default function Input(props: InputProps) { props.paddingX, Boolean(props.styled), ), - } as InputStyle + } as CSSProperties & { + "--tm-md-content-padding"?: string; + } } /> ); @@ -834,7 +827,10 @@ function buildDecorations(view: EditorView): DecorationSet { function addHiddenToken( builder: Range[], selections: ReadonlyArray<{ from: number; to: number }>, - token: TokenRange, + token: { + from: number; + to: number; + }, ): void { if (token.from >= token.to) return; diff --git a/packages/markdown/src/markdown.tsx b/packages/markdown/src/markdown.tsx index 95b4a87..bc64692 100644 --- a/packages/markdown/src/markdown.tsx +++ b/packages/markdown/src/markdown.tsx @@ -1,4 +1,11 @@ -import { Fragment, type ReactElement, type ReactNode } from "react"; +import { + Fragment, + useEffect, + useRef, + useState, + type ReactElement, + type ReactNode, +} from "react"; import Emoji from "./emoji"; import { findEmojiShortcodes } from "./emojiData"; @@ -23,43 +30,11 @@ type InlineTokenRange = { to: number; }; -type ParagraphBlock = { - type: "paragraph"; - text: string; -}; - -type HeadingBlock = { - type: "heading"; - level: number; - text: string; -}; - -type HrBlock = { - type: "hr"; -}; - -type BlockQuoteBlock = { - type: "blockquote"; - text: string; -}; - -type CodeBlock = { - type: "code"; - language: string; - code: string; -}; - type ListItem = { text: string; checked: boolean | null; }; -type ListBlock = { - type: "list"; - ordered: boolean; - items: ListItem[]; -}; - type TableBlock = { type: "table"; headers: string[]; @@ -67,17 +42,140 @@ type TableBlock = { }; type MarkdownBlock = - | ParagraphBlock - | HeadingBlock - | HrBlock - | BlockQuoteBlock - | CodeBlock - | ListBlock + | { + type: "paragraph"; + text: string; + } + | { + type: "heading"; + level: number; + text: string; + } + | { + type: "hr"; + } + | { + type: "blockquote"; + text: string; + } + | { + type: "code"; + language: string; + code: string; + } + | { + type: "list"; + ordered: boolean; + items: ListItem[]; + } | TableBlock; const INLINE_TOKEN_REGEX = /!\[([^\]]*)\]\(([^)\s]+(?:\s+"[^"]*")?)\)|\[([^\]]+)\]\(([^)\s]+(?:\s+"[^"]*")?)\)|`([^`\n]+)`|~~([^~\n]+)~~|\*\*([^*\n]+)\*\*|__([^_\n]+)__|\*([^*\n]+)\*|(? + + Copied + + ); +} + +function CopyableCode({ + block = false, + language, + value, +}: { + block?: boolean; + language?: string; + value: string; +}) { + const [copied, setCopied] = useState(false); + const copiedTimer = useRef | undefined>( + undefined, + ); + + useEffect( + () => () => { + clearTimeout(copiedTimer.current); + }, + [], + ); + + async function copy() { + await navigator.clipboard.writeText(value); + setCopied(true); + clearTimeout(copiedTimer.current); + copiedTimer.current = setTimeout(() => setCopied(false), 1200); + } + + const code = ( + void copy()} + onKeyDown={(event) => { + if (event.key !== "Enter" && event.key !== " ") return; + event.preventDefault(); + void copy(); + }} + > + {value} + + ); + + if (block) { + return ( +
+
{code}
+ +
+ ); + } + + return ( + <> + {code} + + + ); +} + /** * Executes parseInlineNodes. * @param input Parameter input. @@ -429,11 +527,7 @@ function renderInline(nodes: InlineNode[]): ReactNode[] { } if (node.type === "code") { - return ( - - {node.value} - - ); + return ; } if (node.type === "link") { @@ -523,11 +617,12 @@ export function renderBlocks(blocks: MarkdownBlock[]): ReactElement { if (block.type === "code") { return ( -
-              
-                {block.code}
-              
-            
+ ); } @@ -666,7 +761,7 @@ function readTable( } const markdownStyles = ` -.tm-md-root { color: hsl(var(--foreground)); line-height: 1.65; font-size: 1rem; } +.tm-md-root { color: var(--foreground); line-height: 1.65; font-size: 1rem; } .tm-md-heading { margin: 0.2rem 0 0.35rem; font-weight: 700; line-height: 1.25; } .tm-md-h1 { font-size: 1.65rem; } .tm-md-h2 { font-size: 1.45rem; } @@ -676,13 +771,15 @@ const markdownStyles = ` .tm-md-h6 { font-size: 0.95rem; opacity: 0.9; } .tm-md-blockquote { margin: 0.45rem 0; padding-left: 0.75rem; opacity: 0.95; } .tm-md-blockquote p { margin: 0.2rem 0; } -.tm-md-pre { margin: 0.45rem 0; padding: 0.65rem 0.75rem; border-radius: 0.5rem; background: hsl(var(--muted)); overflow-x: auto; } -.tm-md-code, .tm-md-codeblock { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; } -.tm-md-code { padding: 0.08rem 0.32rem; border-radius: 0.28rem; background: hsl(var(--muted)); } +.tm-md-pre { margin: 0.45rem 0; padding: 0.65rem 0.75rem; border-radius: 0.5rem; background: var(--muted); overflow-x: auto; } +.tm-md-code, .tm-md-codeblock { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 0.87em; cursor: pointer; } +.tm-md-code { padding: 0.08rem 0.32rem; border: 1px solid var(--border); border-radius: 0.28rem; background: var(--muted); } +.tm-md-codeblock { display: block; } +.tm-md-code:focus-visible, .tm-md-codeblock:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; } .tm-md-strong { font-weight: 700; } .tm-md-em { font-style: italic; } .tm-md-del { text-decoration: line-through; } -.tm-md-link { color: hsl(var(--primary)); text-decoration: underline; text-underline-offset: 0.14rem; } +.tm-md-link { color: var(--primary); text-decoration: underline; text-underline-offset: 0.14rem; } .tm-md-image { display: block; max-width: 100%; border-radius: 0.4rem; margin: 0.5rem 0; } .tm-md-emoji { display: inline-block; width: 1.15em; height: 1.15em; vertical-align: -0.18em; } .tm-md-ul, .tm-md-ol { margin: 0.3rem 0 0.35rem 1.2rem; padding: 0; } @@ -691,7 +788,7 @@ const markdownStyles = ` .tm-md-table-wrap { overflow-x: auto; margin: 0.45rem 0; } .tm-md-table { border-collapse: collapse; width: 100%; min-width: 16rem; } .tm-md-table th, .tm-md-table td { padding: 0.4rem 0.5rem; text-align: left; } -.tm-md-table th { background: hsl(var(--muted)); font-weight: 600; } +.tm-md-table th { background: var(--muted); font-weight: 600; } .tm-md-hr { margin: 0.55rem 0; } .cm-editor.tm-md-editor { border-radius: inherit; background: transparent; caret-color: var(--foreground); } @@ -699,10 +796,10 @@ const markdownStyles = ` .cm-editor.tm-md-editor .cm-scroller { font-family: inherit; line-height: 1.55; max-height: 30vh; overflow-y: auto; overflow-x: hidden; } .cm-editor.tm-md-editor .cm-content { caret-color: var(--foreground); } .cm-editor.tm-md-editor .cm-content { padding: var(--tm-md-content-padding, 0.25rem 0.625rem); min-height: 2rem; } -.cm-editor.tm-md-editor .cm-line { padding: 0; color: hsl(var(--foreground)); } +.cm-editor.tm-md-editor .cm-line { padding: 0; color: var(--foreground); } .cm-editor.tm-md-editor .tm-md-editor-emoji { display: inline-block; width: 1.15em; height: 1.15em; vertical-align: -0.18em; object-fit: contain; pointer-events: none; } .cm-editor.tm-md-editor .tm-md-hidden-token { color: transparent; opacity: 0; font-size: inherit; } -.cm-editor.tm-md-editor .tm-md-code-line { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; background: hsl(var(--muted)); border-radius: 0.3rem; } +.cm-editor.tm-md-editor .tm-md-code-line { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; background: var(--muted); border-radius: 0.3rem; } .cm-tooltip.cm-tooltip-autocomplete { min-width: 18rem; max-width: min(26rem, calc(100vw - 1rem)); overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius); background: var(--popover); color: var(--popover-foreground); box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); font-family: "Public Sans Variable", sans-serif; font-size: 0.875rem; } .cm-editor.tm-md-editor .cm-tooltip.cm-tooltip-autocomplete > ul { max-height: min(20rem, 45vh); padding: 0.25rem; font-family: "Public Sans Variable", sans-serif; scrollbar-width: thin; scrollbar-color: var(--border) transparent; } .cm-tooltip.cm-tooltip-autocomplete > ul::-webkit-scrollbar { width: 6px; height: 6px; } @@ -726,10 +823,15 @@ export function ensureMarkdownStyles(): void { if (typeof document === "undefined") return; const styleId = "tensamin-markdown-styles"; - if (document.getElementById(styleId)) return; + let style = document.getElementById(styleId) as HTMLStyleElement | null; - const style = document.createElement("style"); - style.id = styleId; - style.textContent = markdownStyles; - document.head.appendChild(style); + if (!style) { + style = document.createElement("style"); + style.id = styleId; + document.head.appendChild(style); + } + + if (style.textContent !== markdownStyles) { + style.textContent = markdownStyles; + } } diff --git a/packages/mtp/src/context.tsx b/packages/mtp/src/context.tsx index 2c9f1e5..69010a9 100644 --- a/packages/mtp/src/context.tsx +++ b/packages/mtp/src/context.tsx @@ -631,16 +631,6 @@ type NativeSnapshot = { error?: string; }; -type NativeEvent = - | { kind: "state"; snapshot: NativeSnapshot } - | { kind: "message"; generation: number; message: unknown } - | { - kind: "log"; - level: number; - message: string; - details?: unknown; - }; - function TauriProvider(props: { children: ReactNode; blockConnection?: boolean; @@ -713,7 +703,16 @@ function TauriProvider(props: { let disposed = false; let unlisten: UnlistenFn | undefined; void (async () => { - unlisten = await listen("mtp://event", ({ payload }) => { + unlisten = await listen< + | { kind: "state"; snapshot: NativeSnapshot } + | { kind: "message"; generation: number; message: unknown } + | { + kind: "log"; + level: number; + message: string; + details?: unknown; + } + >("mtp://event", ({ payload }) => { if (disposed) return; if (payload.kind === "state") { applySnapshot(payload.snapshot); diff --git a/packages/notifications/src/context.tsx b/packages/notifications/src/context.tsx index 453d4e7..a63b906 100644 --- a/packages/notifications/src/context.tsx +++ b/packages/notifications/src/context.tsx @@ -5,7 +5,7 @@ import { useMTP } from "@tensamin/mtp"; import { createContext, useEffect, useContext } from "react"; import { toast as sonnerToast } from "sonner"; import { Avatar, AvatarFallback, AvatarImage } from "@methanium/ui"; -import { isTauri } from "@tauri-apps/api/core"; +import { invoke, isTauri } from "@tauri-apps/api/core"; import { isPermissionGranted as isTauriNotificationPermissionGranted, requestPermission as requestTauriNotificationPermission, @@ -108,7 +108,30 @@ export default function Provider(props: { children: React.ReactNode }) { (await requestTauriNotificationPermission()) === "granted"; if (permissionGranted) { - sendTauriNotification({ title: user.Display, body: content }); + let handledNatively = false; + try { + handledNatively = await invoke( + "mtp_post_message_notification", + { + senderId: user.UserId, + sender: user.Display, + body: content, + avatar: user.Avatar, + }, + ); + } catch (error) { + log( + 1, + "notifications", + "red", + "Failed to create native message notification", + error, + ); + } + + if (!handledNatively) { + sendTauriNotification({ title: user.Display, body: content }); + } } } else { const hasPermissions = await requestNotificationPermission(); diff --git a/packages/onboarding/src/index.tsx b/packages/onboarding/src/index.tsx index da7971e..5efa9c9 100644 --- a/packages/onboarding/src/index.tsx +++ b/packages/onboarding/src/index.tsx @@ -21,10 +21,10 @@ export { type OnboardingStepControls, } from "@methanium/ui"; -type LegalDocs = z.infer; + interface GateState { - docs: LegalDocs; + docs: z.infer; acceptedPP: boolean; acceptedTOS: boolean; includeLegal: boolean; diff --git a/packages/onboarding/src/pages/legal.tsx b/packages/onboarding/src/pages/legal.tsx index 495d143..86c8133 100644 --- a/packages/onboarding/src/pages/legal.tsx +++ b/packages/onboarding/src/pages/legal.tsx @@ -5,7 +5,7 @@ import type { z } from "zod"; import { useOnboardingStep } from "@methanium/ui"; -type LegalDocs = z.infer; + export default function LegalPage({ docs, @@ -13,7 +13,7 @@ export default function LegalPage({ initiallyAcceptedTOS, onAccept, }: { - docs: LegalDocs; + docs: z.infer; initiallyAcceptedPP: boolean; initiallyAcceptedTOS: boolean; onAccept: () => Promise; diff --git a/packages/settings/src/components.tsx b/packages/settings/src/components.tsx index 315ba78..f2ca317 100644 --- a/packages/settings/src/components.tsx +++ b/packages/settings/src/components.tsx @@ -5,9 +5,7 @@ import { storageDefaults, type Storage } from "@tensamin/shared/data"; import { settingsStorageDefaults } from "@tensamin/shared/settings"; import { useStorage } from "@tensamin/storage/context"; -type BooleanStorageKey = { - [K in keyof Storage]: Storage[K] extends boolean ? K : never; -}[keyof Storage]; + type ListStorageKey = { [K in keyof Storage]: Storage[K] extends (string | number)[] ? K : never; @@ -21,7 +19,9 @@ export function Switch({ id, }: { label: React.ReactNode; - id: keyof typeof settingsStorageDefaults & BooleanStorageKey; + id: keyof typeof settingsStorageDefaults & ({ + [K in keyof Storage]: Storage[K] extends boolean ? K : never; +}[keyof Storage]); }) { const { save, load } = useStorage(); const [value, setValue] = useState(settingsStorageDefaults[id]); diff --git a/packages/shared/src/data.ts b/packages/shared/src/data.ts index 4dc5cfd..8480258 100644 --- a/packages/shared/src/data.ts +++ b/packages/shared/src/data.ts @@ -143,25 +143,7 @@ export type Contacts = z.infer; export type Communities = z.infer; export type Calls = z.infer; -type Base16Palette = Record< - | "base00" - | "base01" - | "base02" - | "base03" - | "base04" - | "base05" - | "base06" - | "base07" - | "base08" - | "base09" - | "base0A" - | "base0B" - | "base0C" - | "base0D" - | "base0E" - | "base0F", - string ->; + // MTP const user = z.object({ @@ -472,7 +454,25 @@ export interface Storage extends SettingsStorageDefaults { call_mute_range_start: number; call_mute_range_end: number; theme_color: string; - theme_palette: Base16Palette | null; + theme_palette: Record< + | "base00" + | "base01" + | "base02" + | "base03" + | "base04" + | "base05" + | "base06" + | "base07" + | "base08" + | "base09" + | "base0A" + | "base0B" + | "base0C" + | "base0D" + | "base0E" + | "base0F", + string +> | null; theme_primary_color: string; theme_polarity: "dark" | "light" | "system"; theme_tint: "soft" | "hard" | "extreme"; diff --git a/packages/shared/src/desktopMedia.tsx b/packages/shared/src/desktopMedia.tsx index 75550cd..6799966 100644 --- a/packages/shared/src/desktopMedia.tsx +++ b/packages/shared/src/desktopMedia.tsx @@ -22,7 +22,11 @@ export type DesktopScreenShareCapabilities = { hasReliableSystemAudio: boolean; }; -type ElectronDesktopApi = { + + +declare global { + interface Window { + tensaminDesktop?: { media?: { getScreenShareCapabilities?: () => Promise; listScreenShareSources?: () => Promise; @@ -53,10 +57,6 @@ type ElectronDesktopApi = { clear?: () => Promise; }; }; - -declare global { - interface Window { - tensaminDesktop?: ElectronDesktopApi; } } diff --git a/packages/shared/src/settings.ts b/packages/shared/src/settings.ts index 0c3116b..6fd4d2a 100644 --- a/packages/shared/src/settings.ts +++ b/packages/shared/src/settings.ts @@ -1,14 +1,14 @@ type StringKeyOf = Extract; -type SettingDefinition = { - display: string; - type: string; - default?: unknown; -}; + export type SettingsSchema = Record< string, - Record> + Record> >; const settings = { diff --git a/utils/eslint-rules/index.ts b/utils/eslint-rules/index.ts index 8dee264..ea4eea7 100644 --- a/utils/eslint-rules/index.ts +++ b/utils/eslint-rules/index.ts @@ -72,3 +72,211 @@ export const noWindowLocationReload: Rule.RuleModule = { }; }, }; + +interface AstNode { + type: string; + parent: AstNode | null; + range: [number, number]; +} + +interface TypeAliasDeclaration extends AstNode { + type: "TSTypeAliasDeclaration"; + typeAnnotation: AstNode; + typeParameters?: unknown; +} + +interface FunctionDeclaration extends AstNode { + type: "FunctionDeclaration"; + async: boolean; + generator: boolean; + params: AstNode[]; + body: AstNode & { body: AstNode[] }; +} + +interface ReturnStatement extends AstNode { + type: "ReturnStatement"; + argument: AstNode | null; +} + +function isExported(node: AstNode): boolean { + return ( + node.parent?.type === "ExportNamedDeclaration" || + node.parent?.type === "ExportDefaultDeclaration" + ); +} + +function containsContextSensitiveNode(value: unknown): boolean { + if (!value || typeof value !== "object") return false; + + const node = value as { type?: string; [key: string]: unknown }; + if ( + node.type === "ThisExpression" || + node.type === "Super" || + node.type === "MetaProperty" + ) { + return true; + } + + return Object.entries(node).some( + ([key, child]) => + key !== "parent" && + key !== "loc" && + key !== "range" && + containsContextSensitiveNode(child), + ); +} + +const unambiguousInlineTypes = new Set([ + "TSAnyKeyword", + "TSBigIntKeyword", + "TSBooleanKeyword", + "TSIntrinsicKeyword", + "TSLiteralType", + "TSNeverKeyword", + "TSNullKeyword", + "TSNumberKeyword", + "TSObjectKeyword", + "TSStringKeyword", + "TSSymbolKeyword", + "TSThisType", + "TSTupleType", + "TSTypeLiteral", + "TSTypeReference", + "TSUndefinedKeyword", + "TSUnknownKeyword", + "TSVoidKeyword", +]); + +export const inlineSingleUseDeclarations: Rule.RuleModule = { + meta: { + type: "suggestion", + docs: { + description: "Inline local types and functions that are used only once", + }, + fixable: "code", + messages: { + function: "Inline this function at its only call site.", + type: "Inline this type at its only use site.", + }, + schema: [], + }, + create(context) { + const sourceCode = context.sourceCode; + + return { + TSTypeAliasDeclaration(untypedNode: Rule.Node) { + const node = untypedNode as unknown as TypeAliasDeclaration; + if (node.typeParameters || isExported(node)) return; + + const eslintNode = node as unknown as Rule.Node; + const [variable] = sourceCode.getDeclaredVariables(eslintNode); + if (!variable || variable.references.length !== 1) return; + + const reference = variable.references[0] + .identifier as unknown as AstNode; + if ( + reference.range[0] >= node.range[0] && + reference.range[1] <= node.range[1] + ) { + return; + } + + const referenceParent = reference.parent; + if ( + !referenceParent || + referenceParent.type !== "TSTypeReference" || + referenceParent.parent?.type === "TSClassImplements" || + referenceParent.parent?.type === "TSInterfaceHeritage" + ) { + return; + } + + context.report({ + node: eslintNode, + messageId: "type", + fix(fixer) { + const annotation = sourceCode.getText( + node.typeAnnotation as unknown as Rule.Node, + ); + const replacement = unambiguousInlineTypes.has( + node.typeAnnotation.type, + ) + ? annotation + : `(${annotation})`; + + return [ + fixer.replaceText( + referenceParent as unknown as Rule.Node, + replacement, + ), + fixer.remove(eslintNode), + ]; + }, + }); + }, + + FunctionDeclaration(untypedNode: Rule.Node) { + const node = untypedNode as unknown as FunctionDeclaration; + if ( + node.async || + node.generator || + node.params.length !== 0 || + node.body.body.length !== 1 || + isExported(node) + ) { + return; + } + + const statement = node.body.body[0] as ReturnStatement; + if (statement.type !== "ReturnStatement" || !statement.argument) return; + + const eslintNode = node as unknown as Rule.Node; + const functionScope = sourceCode.getScope(eslintNode); + if ( + functionScope.references.length !== 0 || + functionScope.through.length !== 0 || + containsContextSensitiveNode(statement.argument) + ) { + return; + } + + const [variable] = sourceCode.getDeclaredVariables(eslintNode); + if (!variable || variable.references.length !== 1) return; + + const reference = variable.references[0] + .identifier as unknown as AstNode; + const call = reference.parent; + if ( + !call || + call.type !== "CallExpression" || + (call as AstNode & { callee: AstNode }).callee !== reference || + (call as AstNode & { arguments: AstNode[] }).arguments.length !== 0 || + (call as AstNode & { optional?: boolean }).optional || + (reference.range[0] >= node.range[0] && + reference.range[1] <= node.range[1]) + ) { + return; + } + + context.report({ + node: eslintNode, + messageId: "function", + fix(fixer) { + const expression = sourceCode.getText( + statement.argument! as unknown as Rule.Node, + ); + const replacement = + statement.argument!.type === "Literal" + ? expression + : `(${expression})`; + + return [ + fixer.replaceText(call as unknown as Rule.Node, replacement), + fixer.remove(eslintNode), + ]; + }, + }); + }, + }; + }, +}; diff --git a/utils/scripts/lint-packages.ts b/utils/scripts/lint-packages.ts index 941594c..0aea8c3 100644 --- a/utils/scripts/lint-packages.ts +++ b/utils/scripts/lint-packages.ts @@ -36,7 +36,7 @@ for (const targetDir of targetDirs) { const entry = relative(rootDir, fullPath); console.log(`Linting ${entry}...`); try { - execSync("pnpm run lint", { cwd: fullPath, stdio: "inherit" }); + execSync("pnpm run lint --fix", { cwd: fullPath, stdio: "inherit" }); console.log(`${entry} linted successfully.`); } catch { console.error(`Failed to lint ${entry}.`); From 5fb884edb08cff5c79c3c89d57c315e2f9819a6a Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Wed, 5 Aug 2026 22:00:59 +0200 Subject: [PATCH 15/97] chore(deps): update mtp-transport digest to a81ac4e --- apps/tauri/src-tauri/Cargo.lock | 118 +++++++++++++++++++++++++------- apps/tauri/src-tauri/Cargo.toml | 2 +- 2 files changed, 95 insertions(+), 25 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index 2b557e6..b4587f1 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -2808,12 +2808,12 @@ version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" dependencies = [ "mtp-client", - "mtp-codec", - "mtp-common", - "mtp-crypto", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", "mtp-host", - "mtp-transport", - "mtp-type-map", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", "mtp-webserver", ] @@ -2822,14 +2822,26 @@ name = "mtp-client" version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" dependencies = [ - "mtp-codec", - "mtp-common", - "mtp-crypto", - "mtp-transport", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", "rand 0.10.2", "tokio", ] +[[package]] +name = "mtp-codec" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" +dependencies = [ + "base64 0.22.1", + "byteorder", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", + "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", + "rand 0.10.2", +] + [[package]] name = "mtp-codec" version = "0.2.0" @@ -2837,12 +2849,23 @@ source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14 dependencies = [ "base64 0.22.1", "byteorder", - "mtp-common", - "mtp-crypto", - "mtp-type-map", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", "rand 0.10.2", ] +[[package]] +name = "mtp-common" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" +dependencies = [ + "quinn", + "rustls", + "thiserror 2.0.18", + "wtransport", +] + [[package]] name = "mtp-common" version = "0.2.0" @@ -2854,6 +2877,26 @@ dependencies = [ "wtransport", ] +[[package]] +name = "mtp-crypto" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" +dependencies = [ + "base64 0.22.1", + "chacha20poly1305", + "ed25519-dalek", + "getrandom 0.4.3", + "hkdf", + "ml-dsa", + "rand 0.10.2", + "rand_core 0.10.1", + "rustls", + "sha2 0.11.0", + "thiserror 1.0.69", + "tokio", + "zeroize", +] + [[package]] name = "mtp-crypto" version = "0.2.0" @@ -2881,25 +2924,43 @@ name = "mtp-host" version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" dependencies = [ - "mtp-codec", - "mtp-common", - "mtp-crypto", - "mtp-transport", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", "rand 0.8.6", "tokio", "tracing", "wtransport", ] +[[package]] +name = "mtp-transport" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" +dependencies = [ + "async-trait", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", + "rcgen", + "rustls", + "rustls-native-certs", + "sha2 0.11.0", + "tokio", + "tracing", + "wtransport", +] + [[package]] name = "mtp-transport" version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" dependencies = [ "async-trait", - "mtp-codec", - "mtp-common", - "mtp-crypto", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", "rcgen", "rustls", "rustls-native-certs", @@ -2909,6 +2970,15 @@ dependencies = [ "wtransport", ] +[[package]] +name = "mtp-type-map" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" +dependencies = [ + "serde", + "serde_yaml", +] + [[package]] name = "mtp-type-map" version = "0.2.0" @@ -2932,11 +3002,11 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", - "mtp-codec", - "mtp-common", - "mtp-crypto", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", "mtp-host", - "mtp-transport", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", "quinn", "rand 0.10.2", "rustls", @@ -5392,7 +5462,7 @@ dependencies = [ "base64 0.22.1", "jni 0.21.1", "mtp", - "mtp-transport", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", "reqwest 0.12.28", "serde", "serde_json", diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index 3eec774..35e986b 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -25,7 +25,7 @@ base64 = "0.22" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } tokio = { version = "1", features = ["rt-multi-thread", "sync", "time"] } mtp = { git = "https://git.methanium.net/methanium/mtp.git", rev = "d10266198d62ca9e14a8b1a55d2ab108b24e756e", features = ["client", "crypto"] } -mtp-transport = { git = "https://git.methanium.net/methanium/mtp.git", rev = "d10266198d62ca9e14a8b1a55d2ab108b24e756e" } +mtp-transport = { git = "https://git.methanium.net/methanium/mtp.git", rev = "a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" } webpki-root-certs = "1" tauri-plugin-deep-link = "2" tauri-plugin-notification = "2" From b5c5dd722b1dbc163f04bcd314e54ec609d68c50 Mon Sep 17 00:00:00 2001 From: Alois Date: Wed, 5 Aug 2026 22:07:16 +0200 Subject: [PATCH 16/97] (feat): update renovate --- renovate.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 7190a60..6336684 100644 --- a/renovate.json +++ b/renovate.json @@ -1,3 +1,4 @@ { - "$schema": "https://docs.renovatebot.com/renovate-schema.json" + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "baseBranchPatterns": ["dev"] } From 611a4944b6bd081250424f26e8703c8389bd9210 Mon Sep 17 00:00:00 2001 From: Alois Date: Wed, 5 Aug 2026 22:17:08 +0200 Subject: [PATCH 17/97] (feat): update deps --- apps/web/package.json | 4 +-- pnpm-lock.yaml | 72 +++++++++++++++++++++++++++++-------------- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index e21fea3..d0906be 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@base-ui/react": "^1.0.0", - "@base-ui/utils": "0.3.1", + "@base-ui/utils": "0.3.2", "@babel/runtime": "^7.29.2", "@fontsource-variable/inter": "^5.2.8", "@fontsource-variable/public-sans": "^5.2.7", @@ -35,7 +35,7 @@ "@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-use-callback-ref": "^1.1.1", "@radix-ui/react-use-controllable-state": "^1.2.3", - "@radix-ui/react-use-effect-event": "^0.0.2", + "@radix-ui/react-use-effect-event": "^0.0.5", "@radix-ui/react-use-layout-effect": "^1.1.0", "@reduxjs/toolkit": "^2.0.0", "@tailwindcss/vite": "^4.2.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ea17ec6..6bd139b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -132,8 +132,8 @@ importers: specifier: ^1.0.0 version: 1.6.0(@date-fns/tz@1.5.0)(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@base-ui/utils': - specifier: 0.3.1 - version: 0.3.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: 0.3.2 + version: 0.3.2(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@floating-ui/core': specifier: ^1.7.0 version: 1.7.5 @@ -198,8 +198,8 @@ importers: specifier: ^1.2.3 version: 1.2.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-effect-event': - specifier: ^0.0.2 - version: 0.0.2(@types/react@19.2.17)(react@19.2.7) + specifier: ^0.0.5 + version: 0.0.5(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': specifier: ^1.1.0 version: 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -1123,6 +1123,16 @@ packages: '@types/react': optional: true + '@base-ui/utils@0.3.2': + resolution: {integrity: sha512-oWy1aq/I2GmYjpl4PhEAhzflF8VPGKgZeq0xAWTbfD5KBWyxcN0ZP2+WHSUm/5Z6lVMBDLReLcoXwSYoRc/zNQ==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + '@bufbuild/protobuf@1.10.1': resolution: {integrity: sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ==} @@ -1468,6 +1478,9 @@ packages: '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + '@floating-ui/utils@0.2.12': + resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} + '@fontsource-variable/inter@5.2.8': resolution: {integrity: sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==} @@ -1782,15 +1795,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-use-effect-event@0.0.3': resolution: {integrity: sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==} peerDependencies: @@ -1800,8 +1804,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + '@radix-ui/react-use-effect-event@0.0.5': + resolution: {integrity: sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -1818,6 +1822,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-layout-effect@1.1.4': + resolution: {integrity: sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@reduxjs/toolkit@2.12.0': resolution: {integrity: sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==} peerDependencies: @@ -5412,6 +5425,17 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + '@base-ui/utils@0.3.2(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@babel/runtime': 7.29.7 + '@floating-ui/utils': 0.2.12 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + reselect: 5.2.0 + use-sync-external-store: 1.6.0(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@bufbuild/protobuf@1.10.1': {} '@codemirror/autocomplete@6.20.3': @@ -5784,6 +5808,8 @@ snapshots: '@floating-ui/utils@0.2.11': {} + '@floating-ui/utils@0.2.12': {} + '@fontsource-variable/inter@5.2.8': {} '@fontsource-variable/public-sans@5.2.7': {} @@ -6128,13 +6154,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.17)(react@19.2.7)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.17)(react@19.2.7) - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.17 - '@radix-ui/react-use-effect-event@0.0.3(@types/react@19.2.17)(react@19.2.7)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -6142,8 +6161,9 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.17)(react@19.2.7)': + '@radix-ui/react-use-effect-event@0.0.5(@types/react@19.2.17)(react@19.2.7)': dependencies: + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 optionalDependencies: '@types/react': 19.2.17 @@ -6154,6 +6174,12 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + '@radix-ui/react-use-layout-effect@1.1.4(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)': dependencies: '@standard-schema/spec': 1.1.0 From e11f46bd7c740f10e0db948f7c6bf1e51ac8e4c4 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Wed, 5 Aug 2026 23:01:16 +0200 Subject: [PATCH 18/97] chore(deps): update tauri-build digest to 0aeadb6 --- apps/tauri/src-tauri/Cargo.lock | 255 ++++++++++++++++++++++++++++---- apps/tauri/src-tauri/Cargo.toml | 2 +- 2 files changed, 231 insertions(+), 26 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index 2b557e6..b97060d 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -611,6 +611,17 @@ dependencies = [ "toml 0.9.12+spec-1.1.0", ] +[[package]] +name = "cargo_toml" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa61aec073ec94791433ddf3df2323ff9d1711557c2a0eefb0f99cb4f8dca520" +dependencies = [ + "semver", + "serde", + "toml 1.1.2+spec-1.1.0", +] + [[package]] name = "cc" version = "1.2.65" @@ -640,6 +651,17 @@ dependencies = [ "uuid", ] +[[package]] +name = "cfb" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a347dcabdae9c31b0825fd6a8bed285ec9c2acb89c47827126d52fa4f59cece3" +dependencies = [ + "fnv", + "uuid", + "web-time", +] + [[package]] name = "cfg-expr" version = "0.15.8" @@ -912,7 +934,20 @@ version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" dependencies = [ - "cssparser-macros", + "cssparser-macros 0.6.1", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98" +dependencies = [ + "cssparser-macros 0.7.0", "dtoa-short", "itoa", "phf", @@ -929,6 +964,16 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "cssparser-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a2a99df6e410a8ff4245aa2006499ea662245f967cc7c0a38c83ef8eb44dbf" +dependencies = [ + "quote", + "syn 2.0.118", +] + [[package]] name = "ctor" version = "0.8.0" @@ -939,6 +984,12 @@ dependencies = [ "dtor", ] +[[package]] +name = "ctor" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d83cb7e7a873830708d6b02a78cd36a592c6fa14bf267b68725103b85c0d77f" + [[package]] name = "ctor-proc-macro" version = "0.0.7" @@ -1202,11 +1253,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" dependencies = [ "bit-set", - "cssparser", + "cssparser 0.36.0", "foldhash", - "html5ever", + "html5ever 0.38.0", "precomputed-hash", - "selectors", + "selectors 0.36.1", + "tendril", +] + +[[package]] +name = "dom_query" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac5fca71e65e94cc718a6e2af65d6e0f9c6027751c2aa562fbb5087fda639bc" +dependencies = [ + "bit-set", + "cssparser 0.37.0", + "foldhash", + "html5ever 0.39.0", + "precomputed-hash", + "selectors 0.38.0", "tendril", ] @@ -2060,7 +2126,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" dependencies = [ "log", - "markup5ever", + "markup5ever 0.38.0", +] + +[[package]] +name = "html5ever" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" +dependencies = [ + "log", + "markup5ever 0.39.0", ] [[package]] @@ -2357,7 +2433,16 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" dependencies = [ - "cfb", + "cfb 0.7.3", +] + +[[package]] +name = "infer" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4200d433cbd5178df7797c9c2e75b348b728e39631cf14520d1e2fc424201f4" +dependencies = [ + "cfb 0.14.0", ] [[package]] @@ -2524,12 +2609,24 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" dependencies = [ - "jsonptr", + "jsonptr 0.6.3", "serde", "serde_json", "thiserror 1.0.69", ] +[[package]] +name = "json-patch" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72" +dependencies = [ + "jsonptr 0.7.1", + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "jsonptr" version = "0.6.3" @@ -2540,6 +2637,16 @@ dependencies = [ "serde_json", ] +[[package]] +name = "jsonptr" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "keccak" version = "0.1.6" @@ -2701,6 +2808,17 @@ dependencies = [ "web_atoms", ] +[[package]] +name = "markup5ever" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + [[package]] name = "memchr" version = "2.8.2" @@ -4407,7 +4525,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" dependencies = [ "bitflags 2.13.0", - "cssparser", + "cssparser 0.36.0", + "derive_more", + "log", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "rustc-hash", + "servo_arc", + "smallvec", +] + +[[package]] +name = "selectors" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adfa1c298912827b8a28b223b3b874357397ae706e6190acd9bf28cee99114d" +dependencies = [ + "bitflags 2.13.0", + "cssparser 0.37.0", "derive_more", "log", "new_debug_unreachable", @@ -5032,7 +5169,7 @@ dependencies = [ "serde_repr", "serialize-to-javascript", "swift-rs", - "tauri-build", + "tauri-build 2.6.3 (git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb)", "tauri-macros", "tauri-runtime", "tauri-runtime-wry", @@ -5050,14 +5187,34 @@ dependencies = [ [[package]] name = "tauri-build" version = "2.6.3" -source = "git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb#20f3f2515c65ca1e115991c3ef3625e2c29c1bbb" +source = "git+https://github.com/tauri-apps/tauri?rev=0aeadb6b2674ecd43f15b5dd6fcace3232f74b8a#0aeadb6b2674ecd43f15b5dd6fcace3232f74b8a" dependencies = [ "anyhow", - "cargo_toml", + "cargo_toml 1.0.0", "dirs", "glob", "heck 0.5.0", - "json-patch", + "json-patch 4.2.0", + "schemars 0.8.22", + "semver", + "serde", + "serde_json", + "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=0aeadb6b2674ecd43f15b5dd6fcace3232f74b8a)", + "tauri-winres", + "walkdir", +] + +[[package]] +name = "tauri-build" +version = "2.6.3" +source = "git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb#20f3f2515c65ca1e115991c3ef3625e2c29c1bbb" +dependencies = [ + "anyhow", + "cargo_toml 0.22.3", + "dirs", + "glob", + "heck 0.5.0", + "json-patch 3.0.1", "schemars 1.2.1", "semver", "serde", @@ -5075,7 +5232,7 @@ dependencies = [ "base64 0.22.1", "brotli", "ico", - "json-patch", + "json-patch 3.0.1", "plist", "png 0.17.16", "proc-macro2", @@ -5275,13 +5432,13 @@ checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" dependencies = [ "anyhow", "cargo_metadata", - "ctor", - "dom_query", + "ctor 0.8.0", + "dom_query 0.27.0", "dunce", "glob", "http", - "infer", - "json-patch", + "infer 0.19.0", + "json-patch 3.0.1", "log", "memchr", "phf", @@ -5299,10 +5456,46 @@ dependencies = [ "thiserror 2.0.18", "toml 1.1.2+spec-1.1.0", "url", - "urlpattern", + "urlpattern 0.3.0", "uuid", ] +[[package]] +name = "tauri-utils" +version = "2.9.3" +source = "git+https://github.com/tauri-apps/tauri?rev=0aeadb6b2674ecd43f15b5dd6fcace3232f74b8a#0aeadb6b2674ecd43f15b5dd6fcace3232f74b8a" +dependencies = [ + "anyhow", + "cargo_metadata", + "ctor 1.0.12", + "dom_query 0.28.0", + "dunce", + "glob", + "http", + "infer 0.22.0", + "json-patch 4.2.0", + "log", + "memchr", + "phf", + "plist", + "proc-macro2", + "quote", + "regex", + "schemars 0.8.22", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.18", + "toml 0.9.12+spec-1.1.0", + "url", + "urlpattern 0.6.0", + "uuid", + "walkdir", +] + [[package]] name = "tauri-utils" version = "2.9.3" @@ -5311,13 +5504,13 @@ dependencies = [ "anyhow", "brotli", "cargo_metadata", - "ctor", - "dom_query", + "ctor 0.8.0", + "dom_query 0.27.0", "dunce", "glob", "http", - "infer", - "json-patch", + "infer 0.19.0", + "json-patch 3.0.1", "log", "memchr", "phf", @@ -5335,7 +5528,7 @@ dependencies = [ "thiserror 2.0.18", "toml 1.1.2+spec-1.1.0", "url", - "urlpattern", + "urlpattern 0.3.0", "uuid", "walkdir", ] @@ -5397,7 +5590,7 @@ dependencies = [ "serde", "serde_json", "tauri", - "tauri-build", + "tauri-build 2.6.3 (git+https://github.com/tauri-apps/tauri?rev=0aeadb6b2674ecd43f15b5dd6fcace3232f74b8a)", "tauri-plugin-barcode-scanner", "tauri-plugin-deep-link", "tauri-plugin-log", @@ -5929,6 +6122,18 @@ dependencies = [ "url", ] +[[package]] +name = "urlpattern" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df16f50ef4cc145211879a3867ba757076b25dfee812040dcb0658bd9ae7904b" +dependencies = [ + "icu_properties", + "regex", + "serde", + "url", +] + [[package]] name = "utf-8" version = "0.7.6" @@ -6657,7 +6862,7 @@ dependencies = [ "cookie", "crossbeam-channel", "dirs", - "dom_query", + "dom_query 0.27.0", "dpi", "dunce", "gdkx11", diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index 3eec774..69a3a41 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -15,7 +15,7 @@ name = "mobile_lib" crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] -tauri-build = { git = "https://github.com/tauri-apps/tauri", rev = "20f3f2515c65ca1e115991c3ef3625e2c29c1bbb", features = [] } +tauri-build = { git = "https://github.com/tauri-apps/tauri", rev = "0aeadb6b2674ecd43f15b5dd6fcace3232f74b8a", features = [] } [dependencies] tauri-plugin-opener = "2" From 2dc5be85e32f8b0414ba68f57b2bcb364a10c12f Mon Sep 17 00:00:00 2001 From: Alois Date: Wed, 5 Aug 2026 23:18:39 +0200 Subject: [PATCH 19/97] (fix): mobile builds --- apps/tauri/src-tauri/Cargo.lock | 1 - apps/tauri/src-tauri/Cargo.toml | 1 - apps/tauri/src-tauri/src/mtp_backend.rs | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index 2b557e6..45a60d4 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -5392,7 +5392,6 @@ dependencies = [ "base64 0.22.1", "jni 0.21.1", "mtp", - "mtp-transport", "reqwest 0.12.28", "serde", "serde_json", diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index 3eec774..0f4e594 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -25,7 +25,6 @@ base64 = "0.22" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } tokio = { version = "1", features = ["rt-multi-thread", "sync", "time"] } mtp = { git = "https://git.methanium.net/methanium/mtp.git", rev = "d10266198d62ca9e14a8b1a55d2ab108b24e756e", features = ["client", "crypto"] } -mtp-transport = { git = "https://git.methanium.net/methanium/mtp.git", rev = "d10266198d62ca9e14a8b1a55d2ab108b24e756e" } webpki-root-certs = "1" tauri-plugin-deep-link = "2" tauri-plugin-notification = "2" diff --git a/apps/tauri/src-tauri/src/mtp_backend.rs b/apps/tauri/src-tauri/src/mtp_backend.rs index 7c65b03..b1cd753 100644 --- a/apps/tauri/src-tauri/src/mtp_backend.rs +++ b/apps/tauri/src-tauri/src/mtp_backend.rs @@ -8,12 +8,11 @@ use base64::{ engine::general_purpose::{STANDARD, STANDARD_NO_PAD}, Engine as _, }; -use mtp::client::{ClientConfig, MTPClient, MTPConnection}; +use mtp::client::{ClientConfig, MTPClient, MTPConnection, Policy, SendMode}; use mtp::codec::{CommunicationType, CommunicationValue, DataType, DataValue, TypeMap}; use mtp::crypto::{ derive_encryption_key, AeadDecrypt, ChaCha20Poly1305, HybridKem, Keyring, PublicKeyBundle, }; -use mtp_transport::{Policy, SendMode}; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use tauri::{AppHandle, Emitter}; From be8ea09cd61299ac3664e61fb74084baa531cb75 Mon Sep 17 00:00:00 2001 From: Alois Date: Wed, 5 Aug 2026 23:58:50 +0200 Subject: [PATCH 20/97] (fix): mobile builds --- apps/tauri/src-tauri/Cargo.lock | 137 ++++++++++-------- apps/tauri/src-tauri/Cargo.toml | 4 +- .../tauri/src-tauri/capabilities/default.json | 3 - 3 files changed, 76 insertions(+), 68 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index 45a60d4..84b15a3 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -603,12 +603,13 @@ dependencies = [ [[package]] name = "cargo_toml" -version = "0.22.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +checksum = "aa61aec073ec94791433ddf3df2323ff9d1711557c2a0eefb0f99cb4f8dca520" dependencies = [ + "semver", "serde", - "toml 0.9.12+spec-1.1.0", + "toml 1.1.2+spec-1.1.0", ] [[package]] @@ -939,6 +940,12 @@ dependencies = [ "dtor", ] +[[package]] +name = "ctor" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d83cb7e7a873830708d6b02a78cd36a592c6fa14bf267b68725103b85c0d77f" + [[package]] name = "ctor-proc-macro" version = "0.0.7" @@ -1366,7 +1373,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -2524,12 +2531,24 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" dependencies = [ - "jsonptr", + "jsonptr 0.6.3", "serde", "serde_json", "thiserror 1.0.69", ] +[[package]] +name = "json-patch" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72" +dependencies = [ + "jsonptr 0.7.1", + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "jsonptr" version = "0.6.3" @@ -2540,6 +2559,16 @@ dependencies = [ "serde_json", ] +[[package]] +name = "jsonptr" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "keccak" version = "0.1.6" @@ -3799,7 +3828,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4189,7 +4218,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4248,7 +4277,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4999,8 +5028,8 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.11.3" -source = "git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb#20f3f2515c65ca1e115991c3ef3625e2c29c1bbb" +version = "2.11.5" +source = "git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41#4af26a3f7f8b692d62cca549bbacd93f5ce90b41" dependencies = [ "anyhow", "bytes", @@ -5036,7 +5065,7 @@ dependencies = [ "tauri-macros", "tauri-runtime", "tauri-runtime-wry", - "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb)", + "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41)", "thiserror 2.0.18", "tokio", "tray-icon", @@ -5050,19 +5079,19 @@ dependencies = [ [[package]] name = "tauri-build" version = "2.6.3" -source = "git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb#20f3f2515c65ca1e115991c3ef3625e2c29c1bbb" +source = "git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41#4af26a3f7f8b692d62cca549bbacd93f5ce90b41" dependencies = [ "anyhow", "cargo_toml", "dirs", "glob", "heck 0.5.0", - "json-patch", + "json-patch 4.2.0", "schemars 1.2.1", "semver", "serde", "serde_json", - "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb)", + "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41)", "tauri-winres", "walkdir", ] @@ -5070,12 +5099,12 @@ dependencies = [ [[package]] name = "tauri-codegen" version = "2.6.3" -source = "git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb#20f3f2515c65ca1e115991c3ef3625e2c29c1bbb" +source = "git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41#4af26a3f7f8b692d62cca549bbacd93f5ce90b41" dependencies = [ "base64 0.22.1", "brotli", "ico", - "json-patch", + "json-patch 4.2.0", "plist", "png 0.17.16", "proc-macro2", @@ -5085,7 +5114,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "syn 2.0.118", - "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb)", + "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41)", "thiserror 2.0.18", "time", "url", @@ -5096,14 +5125,14 @@ dependencies = [ [[package]] name = "tauri-macros" version = "2.6.3" -source = "git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb#20f3f2515c65ca1e115991c3ef3625e2c29c1bbb" +source = "git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41#4af26a3f7f8b692d62cca549bbacd93f5ce90b41" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.118", "tauri-codegen", - "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb)", + "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41)", ] [[package]] @@ -5223,7 +5252,7 @@ dependencies = [ [[package]] name = "tauri-runtime" version = "2.11.3" -source = "git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb#20f3f2515c65ca1e115991c3ef3625e2c29c1bbb" +source = "git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41#4af26a3f7f8b692d62cca549bbacd93f5ce90b41" dependencies = [ "cookie", "dpi", @@ -5235,7 +5264,7 @@ dependencies = [ "raw-window-handle", "serde", "serde_json", - "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb)", + "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41)", "thiserror 2.0.18", "url", "windows", @@ -5243,8 +5272,8 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.11.3" -source = "git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb#20f3f2515c65ca1e115991c3ef3625e2c29c1bbb" +version = "2.11.4" +source = "git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41#4af26a3f7f8b692d62cca549bbacd93f5ce90b41" dependencies = [ "gtk", "http", @@ -5259,7 +5288,7 @@ dependencies = [ "softbuffer", "tao", "tauri-runtime", - "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb)", + "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41)", "url", "webkit2gtk", "webview2-com", @@ -5275,13 +5304,13 @@ checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" dependencies = [ "anyhow", "cargo_metadata", - "ctor", + "ctor 0.8.0", "dom_query", "dunce", "glob", "http", "infer", - "json-patch", + "json-patch 3.0.1", "log", "memchr", "phf", @@ -5299,25 +5328,25 @@ dependencies = [ "thiserror 2.0.18", "toml 1.1.2+spec-1.1.0", "url", - "urlpattern", + "urlpattern 0.3.0", "uuid", ] [[package]] name = "tauri-utils" version = "2.9.3" -source = "git+https://github.com/tauri-apps/tauri?rev=20f3f2515c65ca1e115991c3ef3625e2c29c1bbb#20f3f2515c65ca1e115991c3ef3625e2c29c1bbb" +source = "git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41#4af26a3f7f8b692d62cca549bbacd93f5ce90b41" dependencies = [ "anyhow", "brotli", "cargo_metadata", - "ctor", + "ctor 1.0.12", "dom_query", "dunce", "glob", "http", "infer", - "json-patch", + "json-patch 4.2.0", "log", "memchr", "phf", @@ -5335,7 +5364,7 @@ dependencies = [ "thiserror 2.0.18", "toml 1.1.2+spec-1.1.0", "url", - "urlpattern", + "urlpattern 0.6.0", "uuid", "walkdir", ] @@ -5372,7 +5401,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -5586,21 +5615,6 @@ dependencies = [ "toml_edit 0.20.2", ] -[[package]] -name = "toml" -version = "0.9.12+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" -dependencies = [ - "indexmap 2.14.0", - "serde_core", - "serde_spanned 1.1.1", - "toml_datetime 0.7.5+spec-1.1.0", - "toml_parser", - "toml_writer", - "winnow 0.7.15", -] - [[package]] name = "toml" version = "1.1.2+spec-1.1.0" @@ -5625,15 +5639,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_datetime" -version = "0.7.5+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" -dependencies = [ - "serde_core", -] - [[package]] name = "toml_datetime" version = "1.1.1+spec-1.1.0" @@ -5928,6 +5933,18 @@ dependencies = [ "url", ] +[[package]] +name = "urlpattern" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df16f50ef4cc145211879a3867ba757076b25dfee812040dcb0658bd9ae7904b" +dependencies = [ + "icu_properties", + "regex", + "serde", + "url", +] + [[package]] name = "utf-8" version = "0.7.6" @@ -6250,7 +6267,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -6608,12 +6625,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winnow" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" - [[package]] name = "winnow" version = "1.0.3" diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index 0f4e594..25d0338 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -15,7 +15,7 @@ name = "mobile_lib" crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] -tauri-build = { git = "https://github.com/tauri-apps/tauri", rev = "20f3f2515c65ca1e115991c3ef3625e2c29c1bbb", features = [] } +tauri-build = { git = "https://github.com/tauri-apps/tauri", rev = "4af26a3f7f8b692d62cca549bbacd93f5ce90b41", features = [] } [dependencies] tauri-plugin-opener = "2" @@ -43,4 +43,4 @@ tauri-plugin-barcode-scanner = "2" [patch.crates-io.tauri] git = "https://github.com/tauri-apps/tauri" -rev = "20f3f2515c65ca1e115991c3ef3625e2c29c1bbb" +rev = "4af26a3f7f8b692d62cca549bbacd93f5ce90b41" diff --git a/apps/tauri/src-tauri/capabilities/default.json b/apps/tauri/src-tauri/capabilities/default.json index 73d510a..83f7620 100644 --- a/apps/tauri/src-tauri/capabilities/default.json +++ b/apps/tauri/src-tauri/capabilities/default.json @@ -6,10 +6,7 @@ "main" ], "permissions": [ - "core:default", "opener:default", - "core:window:default", - "core:event:default", "deep-link:default", "notification:default", "log:default" From 16a288725dde5ab58c9b96968a9b5135346f1a20 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 00:01:37 +0200 Subject: [PATCH 21/97] chore(deps): update dependency gradle to v8.14.5 --- .../gen/android/gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tauri/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties b/apps/tauri/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties index c5f9a53..8e0bb4b 100644 --- a/apps/tauri/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties +++ b/apps/tauri/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue May 10 19:22:52 CST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.5-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME From a88bda43ebf5f65d9f2b45e8c8002c5fd9741cf1 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 00:01:50 +0200 Subject: [PATCH 22/97] chore(deps): update rust crate serde to v1.0.229 --- apps/tauri/src-tauri/Cargo.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index 93c653c..a383893 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -4568,9 +4568,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -4590,22 +4590,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] From f2343297e0ef3d3ce482139cda1e10ff7b9a0e2e Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 6 Aug 2026 00:53:44 +0200 Subject: [PATCH 23/97] (feat): bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2558ab8..e7a9815 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tensamin", - "version": "0.0.11", + "version": "0.0.12", "private": true, "packageManager": "pnpm@11.8.0", "workspaces": [ From e35fd3d96d5a8716f98ed1f48cfcbf528aa7e4bb Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 02:01:43 +0200 Subject: [PATCH 24/97] chore(deps): update dependency @tanstack/devtools-event-client to ^0.5.0 --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index d0906be..d2a7a83 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -39,7 +39,7 @@ "@radix-ui/react-use-layout-effect": "^1.1.0", "@reduxjs/toolkit": "^2.0.0", "@tailwindcss/vite": "^4.2.4", - "@tanstack/devtools-event-client": "^0.3.0", + "@tanstack/devtools-event-client": "^0.5.0", "@tanstack/query-core": "^5.0.0", "@tanstack/react-router": "^1.169.1", "@tanstack/history": "1.162.0", From d30f7100b14ae1ba6028d2b5ccd79bc256f94491 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 03:00:56 +0200 Subject: [PATCH 25/97] chore(deps): update mtp digest to 7182272 --- apps/tauri/src-tauri/Cargo.lock | 199 +++++++++++++++----------------- apps/tauri/src-tauri/Cargo.toml | 2 +- 2 files changed, 93 insertions(+), 108 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index 86f1b5b..f36c6fd 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -315,6 +315,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "base64ct" version = "1.8.3" @@ -2734,31 +2740,44 @@ dependencies = [ [[package]] name = "mtp" version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ "mtp-client", - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", "mtp-host", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", "mtp-webserver", ] [[package]] name = "mtp-client" version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", "rand 0.10.2", "tokio", ] +[[package]] +name = "mtp-codec" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" +dependencies = [ + "base64 0.23.1", + "byteorder", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "rand 0.10.2", +] + [[package]] name = "mtp-codec" version = "0.2.0" @@ -2772,16 +2791,14 @@ dependencies = [ ] [[package]] -name = "mtp-codec" +name = "mtp-common" version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ - "base64 0.22.1", - "byteorder", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "rand 0.10.2", + "quinn", + "rustls", + "thiserror 2.0.19", + "wtransport", ] [[package]] @@ -2795,43 +2812,12 @@ dependencies = [ "wtransport", ] -[[package]] -name = "mtp-common" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" -dependencies = [ - "quinn", - "rustls", - "thiserror 2.0.19", - "wtransport", -] - [[package]] name = "mtp-crypto" version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ - "base64 0.22.1", - "chacha20poly1305", - "ed25519-dalek", - "getrandom 0.4.3", - "hkdf", - "ml-dsa", - "rand 0.10.2", - "rand_core 0.10.1", - "rustls", - "sha2 0.11.0", - "thiserror 1.0.69", - "tokio", - "zeroize", -] - -[[package]] -name = "mtp-crypto" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" -dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "chacha20poly1305", "ed25519-dalek", "getrandom 0.4.3", @@ -2848,16 +2834,54 @@ dependencies = [ "zeroize", ] +[[package]] +name = "mtp-crypto" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" +dependencies = [ + "base64 0.22.1", + "chacha20poly1305", + "ed25519-dalek", + "getrandom 0.4.3", + "hkdf", + "ml-dsa", + "rand 0.10.2", + "rand_core 0.10.1", + "rustls", + "sha2 0.11.0", + "thiserror 1.0.69", + "tokio", + "zeroize", +] + [[package]] name = "mtp-host" version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "rand 0.8.7", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "rand 0.10.2", + "tokio", + "tracing", + "wtransport", +] + +[[package]] +name = "mtp-transport" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" +dependencies = [ + "async-trait", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "rcgen", + "rustls", + "rustls-native-certs", + "sha2 0.11.0", "tokio", "tracing", "wtransport", @@ -2882,21 +2906,12 @@ dependencies = [ ] [[package]] -name = "mtp-transport" +name = "mtp-type-map" version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ - "async-trait", - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "rcgen", - "rustls", - "rustls-native-certs", - "sha2 0.11.0", - "tokio", - "tracing", - "wtransport", + "serde", + "serde_yaml", ] [[package]] @@ -2908,19 +2923,10 @@ dependencies = [ "serde_yaml", ] -[[package]] -name = "mtp-type-map" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" -dependencies = [ - "serde", - "serde_yaml", -] - [[package]] name = "mtp-webserver" version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e#d10266198d62ca9e14a8b1a55d2ab108b24e756e" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ "async-trait", "bytes", @@ -2931,11 +2937,11 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", "mtp-host", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=d10266198d62ca9e14a8b1a55d2ab108b24e756e)", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", "quinn", "rand 0.10.2", "rustls", @@ -3802,24 +3808,13 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" -[[package]] -name = "rand" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - [[package]] name = "rand" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ - "rand_chacha 0.9.0", + "rand_chacha", "rand_core 0.9.5", ] @@ -3834,16 +3829,6 @@ dependencies = [ "rand_core 0.10.1", ] -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - [[package]] name = "rand_chacha" version = "0.9.0" diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index 9160d2c..78acd24 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -24,7 +24,7 @@ serde_json = "1" base64 = "0.22" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } tokio = { version = "1", features = ["rt-multi-thread", "sync", "time"] } -mtp = { git = "https://git.methanium.net/methanium/mtp.git", rev = "d10266198d62ca9e14a8b1a55d2ab108b24e756e", features = ["client", "crypto"] } +mtp = { git = "https://git.methanium.net/methanium/mtp.git", rev = "7182272e3edb0079d7b74b45b2f62a298d2fee22", features = ["client", "crypto"] } mtp-transport = { git = "https://git.methanium.net/methanium/mtp.git", rev = "a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" } webpki-root-certs = "1" tauri-plugin-deep-link = "2" From faebd27286551480d34bb03fc0417f2045ed2d7d Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 03:01:43 +0200 Subject: [PATCH 26/97] chore(deps): update dependency @tanstack/react-store to ^0.11.0 --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index d0906be..bb6968b 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -43,7 +43,7 @@ "@tanstack/query-core": "^5.0.0", "@tanstack/react-router": "^1.169.1", "@tanstack/history": "1.162.0", - "@tanstack/react-store": "^0.9.3", + "@tanstack/react-store": "^0.11.0", "@tanstack/router-core": "^1.169.1", "@tanstack/store": "^0.9.3", "@tanstack/virtual-core": "^3.13.24", From 2faf100fa27286576aed20ef2be805adc6ff9b60 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 03:01:45 +0200 Subject: [PATCH 27/97] chore(deps): update dependency @tanstack/store to ^0.11.0 --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index d0906be..3877490 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -45,7 +45,7 @@ "@tanstack/history": "1.162.0", "@tanstack/react-store": "^0.9.3", "@tanstack/router-core": "^1.169.1", - "@tanstack/store": "^0.9.3", + "@tanstack/store": "^0.11.0", "@tanstack/virtual-core": "^3.13.24", "@tanstack/react-virtual": "^3.13.24", "@tauri-apps/api": "^2", From f14bfe6233b3a044e37d48597a316da4b34ebff9 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 04:00:54 +0200 Subject: [PATCH 28/97] chore(deps): update mtp-transport digest to 7182272 --- apps/tauri/src-tauri/Cargo.lock | 118 +++++++------------------------- apps/tauri/src-tauri/Cargo.toml | 2 +- 2 files changed, 25 insertions(+), 95 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index f36c6fd..cb0811e 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -2743,12 +2743,12 @@ version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ "mtp-client", - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-codec", + "mtp-common", + "mtp-crypto", "mtp-host", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-transport", + "mtp-type-map", "mtp-webserver", ] @@ -2757,10 +2757,10 @@ name = "mtp-client" version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-codec", + "mtp-common", + "mtp-crypto", + "mtp-transport", "rand 0.10.2", "tokio", ] @@ -2772,21 +2772,9 @@ source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7 dependencies = [ "base64 0.23.1", "byteorder", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "rand 0.10.2", -] - -[[package]] -name = "mtp-codec" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" -dependencies = [ - "base64 0.22.1", - "byteorder", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", - "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", + "mtp-common", + "mtp-crypto", + "mtp-type-map", "rand 0.10.2", ] @@ -2801,17 +2789,6 @@ dependencies = [ "wtransport", ] -[[package]] -name = "mtp-common" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" -dependencies = [ - "quinn", - "rustls", - "thiserror 2.0.19", - "wtransport", -] - [[package]] name = "mtp-crypto" version = "0.2.0" @@ -2834,35 +2811,15 @@ dependencies = [ "zeroize", ] -[[package]] -name = "mtp-crypto" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" -dependencies = [ - "base64 0.22.1", - "chacha20poly1305", - "ed25519-dalek", - "getrandom 0.4.3", - "hkdf", - "ml-dsa", - "rand 0.10.2", - "rand_core 0.10.1", - "rustls", - "sha2 0.11.0", - "thiserror 1.0.69", - "tokio", - "zeroize", -] - [[package]] name = "mtp-host" version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-codec", + "mtp-common", + "mtp-crypto", + "mtp-transport", "rand 0.10.2", "tokio", "tracing", @@ -2875,27 +2832,9 @@ version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ "async-trait", - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "rcgen", - "rustls", - "rustls-native-certs", - "sha2 0.11.0", - "tokio", - "tracing", - "wtransport", -] - -[[package]] -name = "mtp-transport" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" -dependencies = [ - "async-trait", - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", + "mtp-codec", + "mtp-common", + "mtp-crypto", "rcgen", "rustls", "rustls-native-certs", @@ -2914,15 +2853,6 @@ dependencies = [ "serde_yaml", ] -[[package]] -name = "mtp-type-map" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec#a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" -dependencies = [ - "serde", - "serde_yaml", -] - [[package]] name = "mtp-webserver" version = "0.2.0" @@ -2937,11 +2867,11 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-codec", + "mtp-common", + "mtp-crypto", "mtp-host", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-transport", "quinn", "rand 0.10.2", "rustls", @@ -5291,7 +5221,7 @@ dependencies = [ "base64 0.22.1", "jni 0.21.1", "mtp", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=a81ac4efca46fbf0e708c1a0f184735fc9bf7fec)", + "mtp-transport", "reqwest 0.12.28", "serde", "serde_json", diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index 78acd24..e4a401c 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -25,7 +25,7 @@ base64 = "0.22" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } tokio = { version = "1", features = ["rt-multi-thread", "sync", "time"] } mtp = { git = "https://git.methanium.net/methanium/mtp.git", rev = "7182272e3edb0079d7b74b45b2f62a298d2fee22", features = ["client", "crypto"] } -mtp-transport = { git = "https://git.methanium.net/methanium/mtp.git", rev = "a81ac4efca46fbf0e708c1a0f184735fc9bf7fec" } +mtp-transport = { git = "https://git.methanium.net/methanium/mtp.git", rev = "7182272e3edb0079d7b74b45b2f62a298d2fee22" } webpki-root-certs = "1" tauri-plugin-deep-link = "2" tauri-plugin-notification = "2" From 4e97368f2fcf8cde15d4eac6794a7aa91b33cb42 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 05:01:02 +0200 Subject: [PATCH 29/97] chore(deps): update tauri-build digest to c0bd0d5 --- apps/tauri/src-tauri/Cargo.lock | 182 +++++++++++++++++++++++++++++--- apps/tauri/src-tauri/Cargo.toml | 2 +- 2 files changed, 169 insertions(+), 15 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index cb0811e..cacb50d 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -560,6 +560,17 @@ dependencies = [ "uuid", ] +[[package]] +name = "cfb" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a347dcabdae9c31b0825fd6a8bed285ec9c2acb89c47827126d52fa4f59cece3" +dependencies = [ + "fnv", + "uuid", + "web-time", +] + [[package]] name = "cfg-expr" version = "0.15.8" @@ -832,7 +843,20 @@ version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" dependencies = [ - "cssparser-macros", + "cssparser-macros 0.6.1", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98" +dependencies = [ + "cssparser-macros 0.7.0", "dtoa-short", "itoa", "phf", @@ -849,6 +873,16 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "cssparser-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a2a99df6e410a8ff4245aa2006499ea662245f967cc7c0a38c83ef8eb44dbf" +dependencies = [ + "quote", + "syn 2.0.119", +] + [[package]] name = "ctor" version = "0.8.0" @@ -1128,11 +1162,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" dependencies = [ "bit-set", - "cssparser", + "cssparser 0.36.0", "foldhash", - "html5ever", + "html5ever 0.38.0", "precomputed-hash", - "selectors", + "selectors 0.36.1", + "tendril", +] + +[[package]] +name = "dom_query" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac5fca71e65e94cc718a6e2af65d6e0f9c6027751c2aa562fbb5087fda639bc" +dependencies = [ + "bit-set", + "cssparser 0.37.0", + "foldhash", + "html5ever 0.39.0", + "precomputed-hash", + "selectors 0.38.0", "tendril", ] @@ -1976,7 +2025,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" dependencies = [ "log", - "markup5ever", + "markup5ever 0.38.0", +] + +[[package]] +name = "html5ever" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" +dependencies = [ + "log", + "markup5ever 0.39.0", ] [[package]] @@ -2273,7 +2332,16 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" dependencies = [ - "cfb", + "cfb 0.7.3", +] + +[[package]] +name = "infer" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4200d433cbd5178df7797c9c2e75b348b728e39631cf14520d1e2fc424201f4" +dependencies = [ + "cfb 0.14.0", ] [[package]] @@ -2636,6 +2704,17 @@ dependencies = [ "web_atoms", ] +[[package]] +name = "markup5ever" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + [[package]] name = "memchr" version = "2.8.3" @@ -4234,7 +4313,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" dependencies = [ "bitflags 2.13.1", - "cssparser", + "cssparser 0.36.0", + "derive_more", + "log", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "rustc-hash", + "servo_arc", + "smallvec", +] + +[[package]] +name = "selectors" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adfa1c298912827b8a28b223b3b874357397ae706e6190acd9bf28cee99114d" +dependencies = [ + "bitflags 2.13.1", + "cssparser 0.37.0", "derive_more", "log", "new_debug_unreachable", @@ -4863,7 +4961,7 @@ dependencies = [ "serde_repr", "serialize-to-javascript", "swift-rs", - "tauri-build", + "tauri-build 2.6.3 (git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41)", "tauri-macros", "tauri-runtime", "tauri-runtime-wry", @@ -4898,6 +4996,26 @@ dependencies = [ "walkdir", ] +[[package]] +name = "tauri-build" +version = "2.6.3" +source = "git+https://github.com/tauri-apps/tauri?rev=c0bd0d5a61eedba5c4783add24455c5028c6f390#c0bd0d5a61eedba5c4783add24455c5028c6f390" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs", + "glob", + "heck 0.5.0", + "json-patch 4.2.0", + "schemars 0.8.22", + "semver", + "serde", + "serde_json", + "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=c0bd0d5a61eedba5c4783add24455c5028c6f390)", + "tauri-winres", + "walkdir", +] + [[package]] name = "tauri-codegen" version = "2.6.3" @@ -5106,11 +5224,11 @@ dependencies = [ "anyhow", "cargo_metadata", "ctor 0.8.0", - "dom_query", + "dom_query 0.27.0", "dunce", "glob", "http", - "infer", + "infer 0.19.0", "json-patch 3.0.1", "log", "memchr", @@ -5142,11 +5260,11 @@ dependencies = [ "brotli", "cargo_metadata", "ctor 1.0.12", - "dom_query", + "dom_query 0.27.0", "dunce", "glob", "http", - "infer", + "infer 0.19.0", "json-patch 4.2.0", "log", "memchr", @@ -5170,6 +5288,42 @@ dependencies = [ "walkdir", ] +[[package]] +name = "tauri-utils" +version = "2.9.3" +source = "git+https://github.com/tauri-apps/tauri?rev=c0bd0d5a61eedba5c4783add24455c5028c6f390#c0bd0d5a61eedba5c4783add24455c5028c6f390" +dependencies = [ + "anyhow", + "cargo_metadata", + "ctor 1.0.12", + "dom_query 0.28.0", + "dunce", + "glob", + "http", + "infer 0.22.0", + "json-patch 4.2.0", + "log", + "memchr", + "phf", + "plist", + "proc-macro2", + "quote", + "regex", + "schemars 0.8.22", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.19", + "toml 1.1.4+spec-1.1.0", + "url", + "urlpattern 0.6.0", + "uuid", + "walkdir", +] + [[package]] name = "tauri-winres" version = "0.3.6" @@ -5226,7 +5380,7 @@ dependencies = [ "serde", "serde_json", "tauri", - "tauri-build", + "tauri-build 2.6.3 (git+https://github.com/tauri-apps/tauri?rev=c0bd0d5a61eedba5c4783add24455c5028c6f390)", "tauri-plugin-barcode-scanner", "tauri-plugin-deep-link", "tauri-plugin-log", @@ -6451,7 +6605,7 @@ dependencies = [ "cookie", "crossbeam-channel", "dirs", - "dom_query", + "dom_query 0.27.0", "dpi", "dunce", "gdkx11", diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index e4a401c..1f1d4fe 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -15,7 +15,7 @@ name = "mobile_lib" crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] -tauri-build = { git = "https://github.com/tauri-apps/tauri", rev = "4af26a3f7f8b692d62cca549bbacd93f5ce90b41", features = [] } +tauri-build = { git = "https://github.com/tauri-apps/tauri", rev = "c0bd0d5a61eedba5c4783add24455c5028c6f390", features = [] } [dependencies] tauri-plugin-opener = "2" From 6c145d293db233e4daea69cce7634e090b4bab98 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 05:01:47 +0200 Subject: [PATCH 30/97] chore(deps): update dependency androidx.activity:activity-ktx to v1.13.0 --- apps/tauri/src-tauri/gen/android/app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tauri/src-tauri/gen/android/app/build.gradle.kts b/apps/tauri/src-tauri/gen/android/app/build.gradle.kts index 3775319..daaed41 100644 --- a/apps/tauri/src-tauri/gen/android/app/build.gradle.kts +++ b/apps/tauri/src-tauri/gen/android/app/build.gradle.kts @@ -76,7 +76,7 @@ rust { dependencies { implementation("androidx.webkit:webkit:1.14.0") implementation("androidx.appcompat:appcompat:1.7.1") - implementation("androidx.activity:activity-ktx:1.10.1") + implementation("androidx.activity:activity-ktx:1.13.0") implementation("com.google.android.material:material:1.12.0") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.4") From 625314cb5a13db3c017915f0e2aeb4b69f6b97ad Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 05:01:48 +0200 Subject: [PATCH 31/97] chore(deps): update dependency androidx.test.espresso:espresso-core to v3.7.0 --- apps/tauri/src-tauri/gen/android/app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tauri/src-tauri/gen/android/app/build.gradle.kts b/apps/tauri/src-tauri/gen/android/app/build.gradle.kts index 3775319..a8ab853 100644 --- a/apps/tauri/src-tauri/gen/android/app/build.gradle.kts +++ b/apps/tauri/src-tauri/gen/android/app/build.gradle.kts @@ -80,7 +80,7 @@ dependencies { implementation("com.google.android.material:material:1.12.0") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.4") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") + androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0") } apply(from = "tauri.build.gradle.kts") \ No newline at end of file From 5914419aee7220b750e641c281506ec9b0cc4bcb Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 06:01:36 +0200 Subject: [PATCH 32/97] chore(deps): update dependency androidx.test.ext:junit to v1.3.0 --- apps/tauri/src-tauri/gen/android/app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tauri/src-tauri/gen/android/app/build.gradle.kts b/apps/tauri/src-tauri/gen/android/app/build.gradle.kts index 3775319..d8e09b9 100644 --- a/apps/tauri/src-tauri/gen/android/app/build.gradle.kts +++ b/apps/tauri/src-tauri/gen/android/app/build.gradle.kts @@ -79,7 +79,7 @@ dependencies { implementation("androidx.activity:activity-ktx:1.10.1") implementation("com.google.android.material:material:1.12.0") testImplementation("junit:junit:4.13.2") - androidTestImplementation("androidx.test.ext:junit:1.1.4") + androidTestImplementation("androidx.test.ext:junit:1.3.0") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") } From d66b40436834fe16e495388a6759af3dc4b2ff93 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 06:01:38 +0200 Subject: [PATCH 33/97] chore(deps): update dependency androidx.webkit:webkit to v1.16.0 --- apps/tauri/src-tauri/gen/android/app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tauri/src-tauri/gen/android/app/build.gradle.kts b/apps/tauri/src-tauri/gen/android/app/build.gradle.kts index 3775319..3a32749 100644 --- a/apps/tauri/src-tauri/gen/android/app/build.gradle.kts +++ b/apps/tauri/src-tauri/gen/android/app/build.gradle.kts @@ -74,7 +74,7 @@ rust { } dependencies { - implementation("androidx.webkit:webkit:1.14.0") + implementation("androidx.webkit:webkit:1.16.0") implementation("androidx.appcompat:appcompat:1.7.1") implementation("androidx.activity:activity-ktx:1.10.1") implementation("com.google.android.material:material:1.12.0") From acc48c1207925c76c215a8bd6f3c8c1a0b2c5bad Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 07:01:40 +0200 Subject: [PATCH 34/97] chore(deps): update dependency com.android.tools.build:gradle to v8.13.2 --- apps/tauri/src-tauri/gen/android/build.gradle.kts | 2 +- apps/tauri/src-tauri/gen/android/buildSrc/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/tauri/src-tauri/gen/android/build.gradle.kts b/apps/tauri/src-tauri/gen/android/build.gradle.kts index dddb93c..89abd58 100644 --- a/apps/tauri/src-tauri/gen/android/build.gradle.kts +++ b/apps/tauri/src-tauri/gen/android/build.gradle.kts @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath("com.android.tools.build:gradle:8.11.0") + classpath("com.android.tools.build:gradle:8.13.2") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") } } diff --git a/apps/tauri/src-tauri/gen/android/buildSrc/build.gradle.kts b/apps/tauri/src-tauri/gen/android/buildSrc/build.gradle.kts index 5c55bba..9edb463 100644 --- a/apps/tauri/src-tauri/gen/android/buildSrc/build.gradle.kts +++ b/apps/tauri/src-tauri/gen/android/buildSrc/build.gradle.kts @@ -18,6 +18,6 @@ repositories { dependencies { compileOnly(gradleApi()) - implementation("com.android.tools.build:gradle:8.11.0") + implementation("com.android.tools.build:gradle:8.13.2") } From 0e2995454ee37385831b6414d230c1d3d7e94695 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 07:01:41 +0200 Subject: [PATCH 35/97] chore(deps): update dependency com.google.android.material:material to v1.14.0 --- apps/tauri/src-tauri/gen/android/app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tauri/src-tauri/gen/android/app/build.gradle.kts b/apps/tauri/src-tauri/gen/android/app/build.gradle.kts index 3775319..4934cc9 100644 --- a/apps/tauri/src-tauri/gen/android/app/build.gradle.kts +++ b/apps/tauri/src-tauri/gen/android/app/build.gradle.kts @@ -77,7 +77,7 @@ dependencies { implementation("androidx.webkit:webkit:1.14.0") implementation("androidx.appcompat:appcompat:1.7.1") implementation("androidx.activity:activity-ktx:1.10.1") - implementation("com.google.android.material:material:1.12.0") + implementation("com.google.android.material:material:1.14.0") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.4") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") From 48f04adfd9b406c6ed3ac1a385d9b8056cbe553b Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 08:01:45 +0200 Subject: [PATCH 36/97] chore(deps): update dependency deepfilternet3-noise-filter to v1.3.0 --- packages/call/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/call/package.json b/packages/call/package.json index 4fafe09..72ae27b 100644 --- a/packages/call/package.json +++ b/packages/call/package.json @@ -25,7 +25,7 @@ "@tensamin/mtp": "workspace:*", "@methanium/ui": "*", "@tensamin/user": "workspace:*", - "deepfilternet3-noise-filter": "1.2.1", + "deepfilternet3-noise-filter": "1.3.0", "livekit-client": "^2.18.8", "lucide-react": "^1.14.0", "react": "^19.2.0", From 959f6638ad006a882b6c5e0979bf3798fdfe3312 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 08:01:48 +0200 Subject: [PATCH 37/97] chore(deps): update dependency esbuild to ^0.28.0 --- apps/electron/package.json | 2 +- apps/web/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/electron/package.json b/apps/electron/package.json index d87c1ca..ea0cd5f 100644 --- a/apps/electron/package.json +++ b/apps/electron/package.json @@ -33,7 +33,7 @@ "@types/node": "^25.9.1", "electron": "^39.2.7", "electron-builder": "^26.0.12", - "esbuild": "^0.25.11", + "esbuild": "^0.28.0", "typescript": "~6.0.3" }, "build": { diff --git a/apps/web/package.json b/apps/web/package.json index a0bc5af..c064fe2 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -136,7 +136,7 @@ "@types/react": "^19.2.2", "@types/react-dom": "^19.2.2", "@vitejs/plugin-react": "^6.0.1", - "esbuild": "^0.25.11", + "esbuild": "^0.28.0", "eslint": "^10.0.3", "globals": "^17.4.0", "typescript": "~6.0.3", From bb25ed83ef113af1af19eef5cbc1852bb01caed2 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 09:01:55 +0200 Subject: [PATCH 38/97] chore(deps): update dependency recharts to v3.10.1 --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index a0bc5af..43e961a 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -108,7 +108,7 @@ "react-remove-scroll-bar": "^2.3.7", "react-resizable-panels": "^4.11.2", "react-style-singleton": "^2.2.3", - "recharts": "3.8.1", + "recharts": "3.10.1", "redux": "^5.0.0", "redux-thunk": "^3.1.0", "reselect": "5.1.1", From 1b17158ad5924bcbb3556ec932d2ce42f84ad9e6 Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 6 Aug 2026 11:46:44 +0200 Subject: [PATCH 39/97] (fix): mobile notification showing "Connected" if the device is offline --- .../android/app/src/main/AndroidManifest.xml | 1 + .../tensamin/client/MtpForegroundService.kt | 37 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/tauri/src-tauri/gen/android/app/src/main/AndroidManifest.xml b/apps/tauri/src-tauri/gen/android/app/src/main/AndroidManifest.xml index cadb4d6..7d05c07 100644 --- a/apps/tauri/src-tauri/gen/android/app/src/main/AndroidManifest.xml +++ b/apps/tauri/src-tauri/gen/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + diff --git a/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/MtpForegroundService.kt b/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/MtpForegroundService.kt index 0c5d9e8..8b41c78 100644 --- a/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/MtpForegroundService.kt +++ b/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/MtpForegroundService.kt @@ -8,15 +8,30 @@ import android.app.Service import android.content.Context import android.content.Intent import android.content.pm.ServiceInfo +import android.net.ConnectivityManager +import android.net.Network +import android.net.NetworkCapabilities import android.os.Build import android.os.IBinder import androidx.core.app.NotificationCompat class MtpForegroundService : Service() { private var started = false + private val networkCallback = object : ConnectivityManager.NetworkCallback() { + override fun onAvailable(network: Network) = refreshNotification() + override fun onLost(network: Network) = refreshNotification() + override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) = + refreshNotification() + } override fun onBind(intent: Intent?): IBinder? = null + override fun onCreate() { + super.onCreate() + getSystemService(ConnectivityManager::class.java) + .registerDefaultNetworkCallback(networkCallback) + } + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { if (intent?.action == ACTION_STOP) { MtpSecureStore.setEnabled(this, false) @@ -28,7 +43,8 @@ class MtpForegroundService : Service() { if (started) return START_STICKY createChannel(this) - val notification = buildNotification(this, "Connecting") + connectionStatus = "Connecting" + val notification = buildNotification(this, displayedStatus(this)) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { startForeground( NOTIFICATION_ID, @@ -65,20 +81,37 @@ class MtpForegroundService : Service() { } override fun onDestroy() { + getSystemService(ConnectivityManager::class.java).unregisterNetworkCallback(networkCallback) if (!MtpSecureStore.isEnabled(this)) NativeMtpBridge.nativeStop() super.onDestroy() } + private fun refreshNotification() { + updateNotification(this, connectionStatus) + } + companion object { private const val CHANNEL_ID = "tensamin-connection" private const val NOTIFICATION_ID = 2201 private const val ACTION_STOP = "net.tensamin.client.STOP_MTP" + @Volatile private var connectionStatus = "Connecting" fun updateNotification(context: Context, status: String) { if (!MtpSecureStore.isEnabled(context)) return + connectionStatus = status createChannel(context) context.getSystemService(NotificationManager::class.java) - .notify(NOTIFICATION_ID, buildNotification(context, status)) + .notify(NOTIFICATION_ID, buildNotification(context, displayedStatus(context))) + } + + private fun displayedStatus(context: Context): String { + val connectivity = context.getSystemService(ConnectivityManager::class.java) + val network = connectivity.activeNetwork ?: return "No network" + val capabilities = connectivity.getNetworkCapabilities(network) ?: return "No network" + return if ( + capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && + capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + ) connectionStatus else "No network" } private fun createChannel(context: Context) { From 8946da05ccb44c78420004adcdbd343d3b2626e7 Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 6 Aug 2026 11:47:22 +0200 Subject: [PATCH 40/97] (temp): go back to 0.0.11 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e7a9815..2558ab8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tensamin", - "version": "0.0.12", + "version": "0.0.11", "private": true, "packageManager": "pnpm@11.8.0", "workspaces": [ From 6dcec11426301e571549139efca8171e00a8df85 Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 6 Aug 2026 11:48:34 +0200 Subject: [PATCH 41/97] (chore): pause renovate updates --- renovate.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 6336684..44b87f6 100644 --- a/renovate.json +++ b/renovate.json @@ -1,4 +1,5 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "baseBranchPatterns": ["dev"] + "baseBranchPatterns": ["dev"], + "enabled": false } From 83427a344e03113603fde788726e40aa52dc37d4 Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 6 Aug 2026 11:50:56 +0200 Subject: [PATCH 42/97] (chore): refresh dependency licenses --- .../LICENSE | 0 licenses/@methanium_ui@0.0.22/LICENSE | 15 + .../LICENSE | 0 .../LICENSE | 0 .../LICENSE | 2 +- .../LICENSE | 0 .../LICENSE | 0 licenses/THIRD_PARTY_NOTICES.md | 68 ++-- .../LICENSE-APACHE | 0 .../LICENSE-MIT | 0 .../LICENSE.md | 0 .../LICENSE | 0 licenses/sbom.cyclonedx.json | 174 +++++----- licenses/third-party-credits.json | 86 ++--- pnpm-lock.yaml | 323 ++++++++++-------- 15 files changed, 357 insertions(+), 311 deletions(-) rename licenses/{@base-ui_utils@0.3.1 => @base-ui_utils@0.3.2}/LICENSE (100%) create mode 100644 licenses/@methanium_ui@0.0.22/LICENSE rename licenses/{@radix-ui_react-use-effect-event@0.0.2 => @radix-ui_react-use-effect-event@0.0.5}/LICENSE (100%) rename licenses/{@tanstack_devtools-event-client@0.3.5 => @tanstack_devtools-event-client@0.5.0}/LICENSE (100%) rename licenses/{tauri-plugin-app-events-api@0.2.0 => @tanstack_react-hotkeys@0.10.0}/LICENSE (96%) rename licenses/{@tanstack_react-store@0.9.3 => @tanstack_react-store@0.11.0}/LICENSE (100%) rename licenses/{@tanstack_store@0.9.3 => @tanstack_store@0.11.0}/LICENSE (100%) rename licenses/{deepfilternet3-noise-filter@1.2.1 => deepfilternet3-noise-filter@1.3.0}/LICENSE-APACHE (100%) rename licenses/{deepfilternet3-noise-filter@1.2.1 => deepfilternet3-noise-filter@1.3.0}/LICENSE-MIT (100%) rename licenses/{esbuild@0.25.12 => esbuild@0.28.1}/LICENSE.md (100%) rename licenses/{recharts@3.8.1 => recharts@3.10.1}/LICENSE (100%) diff --git a/licenses/@base-ui_utils@0.3.1/LICENSE b/licenses/@base-ui_utils@0.3.2/LICENSE similarity index 100% rename from licenses/@base-ui_utils@0.3.1/LICENSE rename to licenses/@base-ui_utils@0.3.2/LICENSE diff --git a/licenses/@methanium_ui@0.0.22/LICENSE b/licenses/@methanium_ui@0.0.22/LICENSE new file mode 100644 index 0000000..e952c84 --- /dev/null +++ b/licenses/@methanium_ui@0.0.22/LICENSE @@ -0,0 +1,15 @@ +Copyright (c) 2025 Methanium + +All rights reserved. + +No part of this software, source code, documentation, or +associated materials may be copied, reproduced, modified, +distributed, published, sublicensed, sold, or used to create +derivative works without prior written permission from the +copyright holder. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY +OF ANY KIND, EXPRESS OR IMPLIED. TO THE MAXIMUM +EXTENT PERMITTED BY LAW, THE COPYRIGHT HOLDER SHALL +NOT BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER +LIABILITY ARISING FROM THE SOFTWARE OR ITS USE. diff --git a/licenses/@radix-ui_react-use-effect-event@0.0.2/LICENSE b/licenses/@radix-ui_react-use-effect-event@0.0.5/LICENSE similarity index 100% rename from licenses/@radix-ui_react-use-effect-event@0.0.2/LICENSE rename to licenses/@radix-ui_react-use-effect-event@0.0.5/LICENSE diff --git a/licenses/@tanstack_devtools-event-client@0.3.5/LICENSE b/licenses/@tanstack_devtools-event-client@0.5.0/LICENSE similarity index 100% rename from licenses/@tanstack_devtools-event-client@0.3.5/LICENSE rename to licenses/@tanstack_devtools-event-client@0.5.0/LICENSE diff --git a/licenses/tauri-plugin-app-events-api@0.2.0/LICENSE b/licenses/@tanstack_react-hotkeys@0.10.0/LICENSE similarity index 96% rename from licenses/tauri-plugin-app-events-api@0.2.0/LICENSE rename to licenses/@tanstack_react-hotkeys@0.10.0/LICENSE index 637004f..8ce4739 100644 --- a/licenses/tauri-plugin-app-events-api@0.2.0/LICENSE +++ b/licenses/@tanstack_react-hotkeys@0.10.0/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 简静凡 +Copyright (c) 2026 Tanner Linsley Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/licenses/@tanstack_react-store@0.9.3/LICENSE b/licenses/@tanstack_react-store@0.11.0/LICENSE similarity index 100% rename from licenses/@tanstack_react-store@0.9.3/LICENSE rename to licenses/@tanstack_react-store@0.11.0/LICENSE diff --git a/licenses/@tanstack_store@0.9.3/LICENSE b/licenses/@tanstack_store@0.11.0/LICENSE similarity index 100% rename from licenses/@tanstack_store@0.9.3/LICENSE rename to licenses/@tanstack_store@0.11.0/LICENSE diff --git a/licenses/THIRD_PARTY_NOTICES.md b/licenses/THIRD_PARTY_NOTICES.md index f9c8103..138d98a 100644 --- a/licenses/THIRD_PARTY_NOTICES.md +++ b/licenses/THIRD_PARTY_NOTICES.md @@ -22,13 +22,13 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@base-ui_react@1.6.0` - Source package dir: `apps/web/node_modules/@base-ui/react` -## @base-ui/utils@0.3.1 +## @base-ui/utils@0.3.2 - License: MIT - Repository: git+https://github.com/mui/base-ui.git - Description: A collection of React utility functions for Base UI. - Included files: LICENSE -- Folder: `licenses/@base-ui_utils@0.3.1` +- Folder: `licenses/@base-ui_utils@0.3.2` - Source package dir: `apps/web/node_modules/@base-ui/utils` ## @codemirror/autocomplete@6.20.3 @@ -163,6 +163,13 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@livekit_components-react@2.9.21` - Source package dir: `packages/call/node_modules/@livekit/components-react` +## @methanium/ui@0.0.22 + +- License: UNKNOWN +- Included files: LICENSE +- Folder: `licenses/@methanium_ui@0.0.22` +- Source package dir: `apps/tauri/node_modules/@methanium/ui` + ## @radix-ui/primitive@1.1.4 - License: MIT @@ -289,13 +296,13 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@radix-ui_react-use-controllable-state@1.2.3` - Source package dir: `apps/web/node_modules/@radix-ui/react-use-controllable-state` -## @radix-ui/react-use-effect-event@0.0.2 +## @radix-ui/react-use-effect-event@0.0.5 - License: MIT - Homepage: https://radix-ui.com/primitives - Repository: git+https://github.com/radix-ui/primitives.git - Included files: LICENSE -- Folder: `licenses/@radix-ui_react-use-effect-event@0.0.2` +- Folder: `licenses/@radix-ui_react-use-effect-event@0.0.5` - Source package dir: `apps/web/node_modules/@radix-ui/react-use-effect-event` ## @radix-ui/react-use-layout-effect@1.1.2 @@ -327,14 +334,14 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@tailwindcss_vite@4.3.2` - Source package dir: `apps/web/node_modules/@tailwindcss/vite` -## @tanstack/devtools-event-client@0.3.5 +## @tanstack/devtools-event-client@0.5.0 - License: MIT - Homepage: https://tanstack.com/devtools -- Repository: https://github.com/TanStack/devtools.git +- Repository: git+https://github.com/TanStack/devtools.git - Description: TanStack Event Client is a lightweight event client for TanStack Devtools event bus. - Included files: LICENSE -- Folder: `licenses/@tanstack_devtools-event-client@0.3.5` +- Folder: `licenses/@tanstack_devtools-event-client@0.5.0` - Source package dir: `apps/web/node_modules/@tanstack/devtools-event-client` ## @tanstack/history@1.162.0 @@ -367,6 +374,16 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@tanstack_query-core@5.101.2` - Source package dir: `apps/web/node_modules/@tanstack/query-core` +## @tanstack/react-hotkeys@0.10.0 + +- License: MIT +- Homepage: https://tanstack.com/hotkeys +- Repository: git+https://github.com/TanStack/hotkeys.git +- Description: React adapter for TanStack Hotkeys +- Included files: LICENSE +- Folder: `licenses/@tanstack_react-hotkeys@0.10.0` +- Source package dir: `packages/hotkeys/node_modules/@tanstack/react-hotkeys` + ## @tanstack/react-query@5.101.2 - License: MIT @@ -387,14 +404,14 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@tanstack_react-router@1.170.17` - Source package dir: `apps/web/node_modules/@tanstack/react-router` -## @tanstack/react-store@0.9.3 +## @tanstack/react-store@0.11.0 - License: MIT - Homepage: https://tanstack.com/store - Repository: https://github.com/TanStack/store.git - Description: Framework agnostic type-safe store w/ reactive framework adapters - Included files: LICENSE -- Folder: `licenses/@tanstack_react-store@0.9.3` +- Folder: `licenses/@tanstack_react-store@0.11.0` - Source package dir: `apps/web/node_modules/@tanstack/react-store` ## @tanstack/react-virtual@3.14.5 @@ -417,14 +434,14 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@tanstack_router-core@1.171.14` - Source package dir: `apps/web/node_modules/@tanstack/router-core` -## @tanstack/store@0.9.3 +## @tanstack/store@0.11.0 - License: MIT - Homepage: https://tanstack.com/store - Repository: git+https://github.com/TanStack/store.git - Description: Framework agnostic type-safe store w/ reactive framework adapters - Included files: LICENSE -- Folder: `licenses/@tanstack_store@0.9.3` +- Folder: `licenses/@tanstack_store@0.11.0` - Source package dir: `apps/web/node_modules/@tanstack/store` ## @tanstack/virtual-core@3.17.3 @@ -492,13 +509,6 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@tauri-apps_plugin-notification@2.3.3` - Source package dir: `apps/tauri/node_modules/@tauri-apps/plugin-notification` -## @tensamin/ui@0.0.41 - -- License: UNKNOWN -- Included files: none found -- Folder: `licenses/@tensamin_ui@0.0.41` -- Source package dir: `apps/tauri/node_modules/@tensamin/ui` - ## @twemoji/api@17.0.3 - License: MIT AND CC-BY-4.0 @@ -743,14 +753,14 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/decimal.js-light@2.5.1` - Source package dir: `apps/web/node_modules/decimal.js-light` -## deepfilternet3-noise-filter@1.2.1 +## deepfilternet3-noise-filter@1.3.0 - License: (Apache-2.0 OR MIT) - Homepage: https://github.com/mezonai/mezon-noise-suppression#readme - Repository: git+https://github.com/mezonai/mezon-noise-suppression.git - Description: Custom audio processor with DeepFilterNet3 noise filtering integrated with LiveKit client - Included files: LICENSE-APACHE, LICENSE-MIT -- Folder: `licenses/deepfilternet3-noise-filter@1.2.1` +- Folder: `licenses/deepfilternet3-noise-filter@1.3.0` - Source package dir: `packages/call/node_modules/deepfilternet3-noise-filter` ## detect-node-es@1.1.0 @@ -841,13 +851,13 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/es-toolkit@1.49.0` - Source package dir: `apps/web/node_modules/es-toolkit` -## esbuild@0.25.12 +## esbuild@0.28.1 - License: MIT - Repository: git+https://github.com/evanw/esbuild.git - Description: An extremely fast JavaScript and CSS bundler and minifier. - Included files: LICENSE.md -- Folder: `licenses/esbuild@0.25.12` +- Folder: `licenses/esbuild@0.28.1` - Source package dir: `apps/electron/node_modules/esbuild` ## eslint@10.6.0 @@ -1108,14 +1118,14 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/react-style-singleton@2.2.3` - Source package dir: `apps/web/node_modules/react-style-singleton` -## recharts@3.8.1 +## recharts@3.10.1 - License: MIT - Homepage: https://github.com/recharts/recharts - Repository: git+https://github.com/recharts/recharts.git - Description: React charts - Included files: LICENSE -- Folder: `licenses/recharts@3.8.1` +- Folder: `licenses/recharts@3.10.1` - Source package dir: `apps/web/node_modules/recharts` ## redux@5.0.1 @@ -1226,16 +1236,6 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/tailwindcss@4.3.2` - Source package dir: `apps/web/node_modules/tailwindcss` -## tauri-plugin-app-events-api@0.2.0 - -- License: MIT -- Homepage: https://github.com/wtto00/tauri-plugin-app-events#readme -- Repository: git+https://github.com/wtto00/tauri-plugin-app-events.git -- Description: A plugin for tauri@v2 to listen some events on iOS and Android. -- Included files: LICENSE -- Folder: `licenses/tauri-plugin-app-events-api@0.2.0` -- Source package dir: `packages/mtp/node_modules/tauri-plugin-app-events-api` - ## tiny-invariant@1.3.3 - License: MIT diff --git a/licenses/deepfilternet3-noise-filter@1.2.1/LICENSE-APACHE b/licenses/deepfilternet3-noise-filter@1.3.0/LICENSE-APACHE similarity index 100% rename from licenses/deepfilternet3-noise-filter@1.2.1/LICENSE-APACHE rename to licenses/deepfilternet3-noise-filter@1.3.0/LICENSE-APACHE diff --git a/licenses/deepfilternet3-noise-filter@1.2.1/LICENSE-MIT b/licenses/deepfilternet3-noise-filter@1.3.0/LICENSE-MIT similarity index 100% rename from licenses/deepfilternet3-noise-filter@1.2.1/LICENSE-MIT rename to licenses/deepfilternet3-noise-filter@1.3.0/LICENSE-MIT diff --git a/licenses/esbuild@0.25.12/LICENSE.md b/licenses/esbuild@0.28.1/LICENSE.md similarity index 100% rename from licenses/esbuild@0.25.12/LICENSE.md rename to licenses/esbuild@0.28.1/LICENSE.md diff --git a/licenses/recharts@3.8.1/LICENSE b/licenses/recharts@3.10.1/LICENSE similarity index 100% rename from licenses/recharts@3.8.1/LICENSE rename to licenses/recharts@3.10.1/LICENSE diff --git a/licenses/sbom.cyclonedx.json b/licenses/sbom.cyclonedx.json index 1c35ba5..d8c89d9 100644 --- a/licenses/sbom.cyclonedx.json +++ b/licenses/sbom.cyclonedx.json @@ -3,7 +3,7 @@ "specVersion": "1.5", "version": 1, "metadata": { - "timestamp": "2026-07-24T10:43:11.914Z", + "timestamp": "2026-08-06T09:49:26.512Z", "tools": [ { "vendor": "OpenAI", @@ -88,10 +88,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40base-ui/utils@0.3.1", + "bomRef": "pkg:npm/%40base-ui/utils@0.3.2", "name": "@base-ui/utils", - "version": "0.3.1", - "purl": "pkg:npm/%40base-ui/utils@0.3.1", + "version": "0.3.2", + "purl": "pkg:npm/%40base-ui/utils@0.3.2", "description": "A collection of React utility functions for Base UI.", "licenses": [ { @@ -109,7 +109,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@base-ui_utils@0.3.1" + "value": "licenses/@base-ui_utils@0.3.2" }, { "name": "local:sourcePackageDir", @@ -578,6 +578,24 @@ } ] }, + { + "type": "library", + "bomRef": "pkg:npm/%40methanium/ui@0.0.22", + "name": "@methanium/ui", + "version": "0.0.22", + "purl": "pkg:npm/%40methanium/ui@0.0.22", + "externalReferences": [], + "properties": [ + { + "name": "local:licenseFolder", + "value": "licenses/@methanium_ui@0.0.22" + }, + { + "name": "local:sourcePackageDir", + "value": "apps/tauri/node_modules/@methanium/ui" + } + ] + }, { "type": "library", "bomRef": "pkg:npm/%40radix-ui/primitive@1.1.4", @@ -1056,10 +1074,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-use-effect-event@0.0.2", + "bomRef": "pkg:npm/%40radix-ui/react-use-effect-event@0.0.5", "name": "@radix-ui/react-use-effect-event", - "version": "0.0.2", - "purl": "pkg:npm/%40radix-ui/react-use-effect-event@0.0.2", + "version": "0.0.5", + "purl": "pkg:npm/%40radix-ui/react-use-effect-event@0.0.5", "licenses": [ { "license": { @@ -1080,7 +1098,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-use-effect-event@0.0.2" + "value": "licenses/@radix-ui_react-use-effect-event@0.0.5" }, { "name": "local:sourcePackageDir", @@ -1194,10 +1212,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40tanstack/devtools-event-client@0.3.5", + "bomRef": "pkg:npm/%40tanstack/devtools-event-client@0.5.0", "name": "@tanstack/devtools-event-client", - "version": "0.3.5", - "purl": "pkg:npm/%40tanstack/devtools-event-client@0.3.5", + "version": "0.5.0", + "purl": "pkg:npm/%40tanstack/devtools-event-client@0.5.0", "description": "TanStack Event Client is a lightweight event client for TanStack Devtools event bus.", "licenses": [ { @@ -1213,13 +1231,13 @@ }, { "type": "vcs", - "url": "https://github.com/TanStack/devtools.git" + "url": "git+https://github.com/TanStack/devtools.git" } ], "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@tanstack_devtools-event-client@0.3.5" + "value": "licenses/@tanstack_devtools-event-client@0.5.0" }, { "name": "local:sourcePackageDir", @@ -1332,6 +1350,41 @@ } ] }, + { + "type": "library", + "bomRef": "pkg:npm/%40tanstack/react-hotkeys@0.10.0", + "name": "@tanstack/react-hotkeys", + "version": "0.10.0", + "purl": "pkg:npm/%40tanstack/react-hotkeys@0.10.0", + "description": "React adapter for TanStack Hotkeys", + "licenses": [ + { + "license": { + "id": "MIT" + } + } + ], + "externalReferences": [ + { + "type": "website", + "url": "https://tanstack.com/hotkeys" + }, + { + "type": "vcs", + "url": "git+https://github.com/TanStack/hotkeys.git" + } + ], + "properties": [ + { + "name": "local:licenseFolder", + "value": "licenses/@tanstack_react-hotkeys@0.10.0" + }, + { + "name": "local:sourcePackageDir", + "value": "packages/hotkeys/node_modules/@tanstack/react-hotkeys" + } + ] + }, { "type": "library", "bomRef": "pkg:npm/%40tanstack/react-query@5.101.2", @@ -1404,10 +1457,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40tanstack/react-store@0.9.3", + "bomRef": "pkg:npm/%40tanstack/react-store@0.11.0", "name": "@tanstack/react-store", - "version": "0.9.3", - "purl": "pkg:npm/%40tanstack/react-store@0.9.3", + "version": "0.11.0", + "purl": "pkg:npm/%40tanstack/react-store@0.11.0", "description": "Framework agnostic type-safe store w/ reactive framework adapters", "licenses": [ { @@ -1429,7 +1482,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@tanstack_react-store@0.9.3" + "value": "licenses/@tanstack_react-store@0.11.0" }, { "name": "local:sourcePackageDir", @@ -1509,10 +1562,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40tanstack/store@0.9.3", + "bomRef": "pkg:npm/%40tanstack/store@0.11.0", "name": "@tanstack/store", - "version": "0.9.3", - "purl": "pkg:npm/%40tanstack/store@0.9.3", + "version": "0.11.0", + "purl": "pkg:npm/%40tanstack/store@0.11.0", "description": "Framework agnostic type-safe store w/ reactive framework adapters", "licenses": [ { @@ -1534,7 +1587,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@tanstack_store@0.9.3" + "value": "licenses/@tanstack_store@0.11.0" }, { "name": "local:sourcePackageDir", @@ -1770,24 +1823,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/%40tensamin/ui@0.0.41", - "name": "@tensamin/ui", - "version": "0.0.41", - "purl": "pkg:npm/%40tensamin/ui@0.0.41", - "externalReferences": [], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@tensamin_ui@0.0.41" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/tauri/node_modules/@tensamin/ui" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/%40twemoji/api@17.0.3", @@ -2647,10 +2682,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/deepfilternet3-noise-filter@1.2.1", + "bomRef": "pkg:npm/deepfilternet3-noise-filter@1.3.0", "name": "deepfilternet3-noise-filter", - "version": "1.2.1", - "purl": "pkg:npm/deepfilternet3-noise-filter@1.2.1", + "version": "1.3.0", + "purl": "pkg:npm/deepfilternet3-noise-filter@1.3.0", "description": "Custom audio processor with DeepFilterNet3 noise filtering integrated with LiveKit client", "licenses": [ { @@ -2672,7 +2707,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/deepfilternet3-noise-filter@1.2.1" + "value": "licenses/deepfilternet3-noise-filter@1.3.0" }, { "name": "local:sourcePackageDir", @@ -2989,10 +3024,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/esbuild@0.25.12", + "bomRef": "pkg:npm/esbuild@0.28.1", "name": "esbuild", - "version": "0.25.12", - "purl": "pkg:npm/esbuild@0.25.12", + "version": "0.28.1", + "purl": "pkg:npm/esbuild@0.28.1", "description": "An extremely fast JavaScript and CSS bundler and minifier.", "licenses": [ { @@ -3010,7 +3045,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/esbuild@0.25.12" + "value": "licenses/esbuild@0.28.1" }, { "name": "local:sourcePackageDir", @@ -3915,10 +3950,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/recharts@3.8.1", + "bomRef": "pkg:npm/recharts@3.10.1", "name": "recharts", - "version": "3.8.1", - "purl": "pkg:npm/recharts@3.8.1", + "version": "3.10.1", + "purl": "pkg:npm/recharts@3.10.1", "description": "React charts", "licenses": [ { @@ -3940,7 +3975,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/recharts@3.8.1" + "value": "licenses/recharts@3.10.1" }, { "name": "local:sourcePackageDir", @@ -4325,41 +4360,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/tauri-plugin-app-events-api@0.2.0", - "name": "tauri-plugin-app-events-api", - "version": "0.2.0", - "purl": "pkg:npm/tauri-plugin-app-events-api@0.2.0", - "description": "A plugin for tauri@v2 to listen some events on iOS and Android.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/wtto00/tauri-plugin-app-events#readme" - }, - { - "type": "vcs", - "url": "git+https://github.com/wtto00/tauri-plugin-app-events.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/tauri-plugin-app-events-api@0.2.0" - }, - { - "name": "local:sourcePackageDir", - "value": "packages/mtp/node_modules/tauri-plugin-app-events-api" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/tiny-invariant@1.3.3", diff --git a/licenses/third-party-credits.json b/licenses/third-party-credits.json index 180e5e4..3481aba 100644 --- a/licenses/third-party-credits.json +++ b/licenses/third-party-credits.json @@ -1,5 +1,5 @@ { - "generatedAt": "2026-07-24T10:43:11.913Z", + "generatedAt": "2026-08-06T09:49:26.511Z", "packageCount": 145, "packages": [ { @@ -30,7 +30,7 @@ }, { "name": "@base-ui/utils", - "version": "0.3.1", + "version": "0.3.2", "license": "MIT", "homepage": null, "repository": "git+https://github.com/mui/base-ui.git", @@ -38,7 +38,7 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@base-ui_utils@0.3.1", + "licenseFolder": "licenses/@base-ui_utils@0.3.2", "sourcePackageDir": "apps/web/node_modules/@base-ui/utils" }, { @@ -223,6 +223,19 @@ "licenseFolder": "licenses/@livekit_components-react@2.9.21", "sourcePackageDir": "packages/call/node_modules/@livekit/components-react" }, + { + "name": "@methanium/ui", + "version": "0.0.22", + "license": "UNKNOWN", + "homepage": null, + "repository": null, + "description": null, + "files": [ + "LICENSE" + ], + "licenseFolder": "licenses/@methanium_ui@0.0.22", + "sourcePackageDir": "apps/tauri/node_modules/@methanium/ui" + }, { "name": "@radix-ui/primitive", "version": "1.1.4", @@ -407,7 +420,7 @@ }, { "name": "@radix-ui/react-use-effect-event", - "version": "0.0.2", + "version": "0.0.5", "license": "MIT", "homepage": "https://radix-ui.com/primitives", "repository": "git+https://github.com/radix-ui/primitives.git", @@ -415,7 +428,7 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@radix-ui_react-use-effect-event@0.0.2", + "licenseFolder": "licenses/@radix-ui_react-use-effect-event@0.0.5", "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-use-effect-event" }, { @@ -459,15 +472,15 @@ }, { "name": "@tanstack/devtools-event-client", - "version": "0.3.5", + "version": "0.5.0", "license": "MIT", "homepage": "https://tanstack.com/devtools", - "repository": "https://github.com/TanStack/devtools.git", + "repository": "git+https://github.com/TanStack/devtools.git", "description": "TanStack Event Client is a lightweight event client for TanStack Devtools event bus.", "files": [ "LICENSE" ], - "licenseFolder": "licenses/@tanstack_devtools-event-client@0.3.5", + "licenseFolder": "licenses/@tanstack_devtools-event-client@0.5.0", "sourcePackageDir": "apps/web/node_modules/@tanstack/devtools-event-client" }, { @@ -509,6 +522,19 @@ "licenseFolder": "licenses/@tanstack_query-core@5.101.2", "sourcePackageDir": "apps/web/node_modules/@tanstack/query-core" }, + { + "name": "@tanstack/react-hotkeys", + "version": "0.10.0", + "license": "MIT", + "homepage": "https://tanstack.com/hotkeys", + "repository": "git+https://github.com/TanStack/hotkeys.git", + "description": "React adapter for TanStack Hotkeys", + "files": [ + "LICENSE" + ], + "licenseFolder": "licenses/@tanstack_react-hotkeys@0.10.0", + "sourcePackageDir": "packages/hotkeys/node_modules/@tanstack/react-hotkeys" + }, { "name": "@tanstack/react-query", "version": "5.101.2", @@ -537,7 +563,7 @@ }, { "name": "@tanstack/react-store", - "version": "0.9.3", + "version": "0.11.0", "license": "MIT", "homepage": "https://tanstack.com/store", "repository": "https://github.com/TanStack/store.git", @@ -545,7 +571,7 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@tanstack_react-store@0.9.3", + "licenseFolder": "licenses/@tanstack_react-store@0.11.0", "sourcePackageDir": "apps/web/node_modules/@tanstack/react-store" }, { @@ -576,7 +602,7 @@ }, { "name": "@tanstack/store", - "version": "0.9.3", + "version": "0.11.0", "license": "MIT", "homepage": "https://tanstack.com/store", "repository": "git+https://github.com/TanStack/store.git", @@ -584,7 +610,7 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@tanstack_store@0.9.3", + "licenseFolder": "licenses/@tanstack_store@0.11.0", "sourcePackageDir": "apps/web/node_modules/@tanstack/store" }, { @@ -680,17 +706,6 @@ "licenseFolder": "licenses/@tauri-apps_plugin-notification@2.3.3", "sourcePackageDir": "apps/tauri/node_modules/@tauri-apps/plugin-notification" }, - { - "name": "@tensamin/ui", - "version": "0.0.41", - "license": "UNKNOWN", - "homepage": null, - "repository": null, - "description": null, - "files": [], - "licenseFolder": "licenses/@tensamin_ui@0.0.41", - "sourcePackageDir": "apps/tauri/node_modules/@tensamin/ui" - }, { "name": "@twemoji/api", "version": "17.0.3", @@ -1018,7 +1033,7 @@ }, { "name": "deepfilternet3-noise-filter", - "version": "1.2.1", + "version": "1.3.0", "license": "(Apache-2.0 OR MIT)", "homepage": "https://github.com/mezonai/mezon-noise-suppression#readme", "repository": "git+https://github.com/mezonai/mezon-noise-suppression.git", @@ -1027,7 +1042,7 @@ "LICENSE-APACHE", "LICENSE-MIT" ], - "licenseFolder": "licenses/deepfilternet3-noise-filter@1.2.1", + "licenseFolder": "licenses/deepfilternet3-noise-filter@1.3.0", "sourcePackageDir": "packages/call/node_modules/deepfilternet3-noise-filter" }, { @@ -1143,7 +1158,7 @@ }, { "name": "esbuild", - "version": "0.25.12", + "version": "0.28.1", "license": "MIT", "homepage": null, "repository": "git+https://github.com/evanw/esbuild.git", @@ -1151,7 +1166,7 @@ "files": [ "LICENSE.md" ], - "licenseFolder": "licenses/esbuild@0.25.12", + "licenseFolder": "licenses/esbuild@0.28.1", "sourcePackageDir": "apps/electron/node_modules/esbuild" }, { @@ -1499,7 +1514,7 @@ }, { "name": "recharts", - "version": "3.8.1", + "version": "3.10.1", "license": "MIT", "homepage": "https://github.com/recharts/recharts", "repository": "git+https://github.com/recharts/recharts.git", @@ -1507,7 +1522,7 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/recharts@3.8.1", + "licenseFolder": "licenses/recharts@3.10.1", "sourcePackageDir": "apps/web/node_modules/recharts" }, { @@ -1653,19 +1668,6 @@ "licenseFolder": "licenses/tailwindcss@4.3.2", "sourcePackageDir": "apps/web/node_modules/tailwindcss" }, - { - "name": "tauri-plugin-app-events-api", - "version": "0.2.0", - "license": "MIT", - "homepage": "https://github.com/wtto00/tauri-plugin-app-events#readme", - "repository": "git+https://github.com/wtto00/tauri-plugin-app-events.git", - "description": "A plugin for tauri@v2 to listen some events on iOS and Android.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/tauri-plugin-app-events-api@0.2.0", - "sourcePackageDir": "packages/mtp/node_modules/tauri-plugin-app-events-api" - }, { "name": "tiny-invariant", "version": "1.3.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6bd139b..6a529ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,7 +63,7 @@ importers: version: 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) vitest: specifier: ^4.0.8 - version: 4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) yaml: specifier: ^2.8.2 version: 2.9.0 @@ -80,8 +80,8 @@ importers: specifier: ^26.0.12 version: 26.15.3(electron-builder-squirrel-windows@26.15.3) esbuild: - specifier: ^0.25.11 - version: 0.25.12 + specifier: ^0.28.0 + version: 0.28.1 typescript: specifier: ~6.0.3 version: 6.0.3 @@ -208,10 +208,10 @@ importers: version: 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7))(react@19.2.7) '@tailwindcss/vite': specifier: ^4.2.4 - version: 4.3.2(vite@8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.3.2(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) '@tanstack/devtools-event-client': - specifier: ^0.3.0 - version: 0.3.5 + specifier: ^0.5.0 + version: 0.5.0 '@tanstack/history': specifier: 1.162.0 version: 1.162.0 @@ -222,8 +222,8 @@ importers: specifier: ^1.169.1 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tanstack/react-store': - specifier: ^0.9.3 - version: 0.9.3(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: ^0.11.0 + version: 0.11.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tanstack/react-virtual': specifier: ^3.13.24 version: 3.14.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -231,8 +231,8 @@ importers: specifier: ^1.169.1 version: 1.171.14 '@tanstack/store': - specifier: ^0.9.3 - version: 0.9.3 + specifier: ^0.11.0 + version: 0.11.0 '@tanstack/virtual-core': specifier: ^3.13.24 version: 3.17.3 @@ -411,8 +411,8 @@ importers: specifier: ^2.2.3 version: 2.2.3(@types/react@19.2.17)(react@19.2.7) recharts: - specifier: 3.8.1 - version: 3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1) + specifier: 3.10.1 + version: 3.10.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1) redux: specifier: ^5.0.0 version: 5.0.1 @@ -491,10 +491,10 @@ importers: version: 19.2.3(@types/react@19.2.17) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.3(vite@8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0)) + version: 6.0.3(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) esbuild: - specifier: ^0.25.11 - version: 0.25.12 + specifier: ^0.28.0 + version: 0.28.1 eslint: specifier: ^10.0.3 version: 10.6.0(jiti@2.7.0) @@ -509,7 +509,7 @@ importers: version: 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) vite: specifier: ^8.0.10 - version: 8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0) + version: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) packages/cache: dependencies: @@ -556,8 +556,8 @@ importers: specifier: workspace:* version: link:../user deepfilternet3-noise-filter: - specifier: 1.2.1 - version: 1.2.1(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22)) + specifier: 1.3.0 + version: 1.3.0(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22)) livekit-client: specifier: ^2.18.8 version: 2.20.0(@types/dom-mediacapture-record@1.0.22) @@ -663,7 +663,7 @@ importers: devDependencies: vite: specifier: ^8.0.10 - version: 8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0) + version: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) packages/markdown: dependencies: @@ -854,7 +854,7 @@ importers: devDependencies: vite: specifier: ^8.0.10 - version: 8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0) + version: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) packages/shared: dependencies: @@ -1225,158 +1225,158 @@ packages: '@emnapi/wasi-threads@1.2.2': resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + '@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.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + '@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.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + '@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.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + '@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.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + '@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.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + '@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.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -2055,15 +2055,16 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/devtools-event-client@0.3.5': - resolution: {integrity: sha512-RL1f5ZlfZMpghrCIdzl6mLOFLTuhqmPNblZgBaeKfdtk5rfbjykurv+VfYydOFXj0vxVIoA2d/zT7xfD7Ph8fw==} - engines: {node: '>=18'} - '@tanstack/devtools-event-client@0.4.4': resolution: {integrity: sha512-6T5Yop/793YI+H+5J8Hsyj4kCih9sl4t3ElLgKioW5hk3ocn+ZdSJ94tT7vL7uabxSugWYBZlOTMPzEw2puvQw==} engines: {node: '>=18'} hasBin: true + '@tanstack/devtools-event-client@0.5.0': + resolution: {integrity: sha512-H+OH3zC6Vhu/K0NaVfQKknEKawc/+2PT+D3SB3Ox0V8SiMlTo0abbmH2rH0721R2aNYbjdMXA1oENOd8E2UVoA==} + engines: {node: '>=18'} + hasBin: true + '@tanstack/history@1.162.0': resolution: {integrity: sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==} engines: {node: '>=20.19'} @@ -2891,8 +2892,8 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - deepfilternet3-noise-filter@1.2.1: - resolution: {integrity: sha512-OAyrHTDlUHH+AhfpVNKYEOhVqb9cZpu0fdNThplA/tB/Ts4PF/UsI+abl2n1IbSxUkhiF0OqDejEhk1n42Oqpw==} + deepfilternet3-noise-filter@1.3.0: + resolution: {integrity: sha512-yYFUlPuvPguqcd/R6/OSsr0noGqlqOE50JkCWYHogk+PjLj9qrNgwTt5zKraVkKnw0l4+eXJagkz2SUWtUl4sQ==} engines: {node: '>=18.0.0'} peerDependencies: livekit-client: ^2.0.0 @@ -3095,8 +3096,8 @@ packages: es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} hasBin: true @@ -4472,6 +4473,14 @@ packages: resolution: {integrity: sha512-dEWRjcINDu/F4l2dYx57ugBtD7HV9KXESyxhzw/MqWLeglJrsjJKqACPyUPg+6AF8mIgm+Zi0dZ3ACoIg+QtpA==} engines: {node: '>= 4'} + recharts@3.10.1: + resolution: {integrity: sha512-QXFrvt6IVcw7eeZCoyXTwkIJAX3Dv1nyVhMicXJ47GsGDDpcN8z6o644DibE9XjpBTThtsomLKnTV6lc+cVFUA==} + engines: {node: '>=18'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + recharts@3.8.1: resolution: {integrity: sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==} engines: {node: '>=18'} @@ -5650,82 +5659,82 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.25.12': + '@esbuild/aix-ppc64@0.28.1': optional: true - '@esbuild/android-arm64@0.25.12': + '@esbuild/android-arm64@0.28.1': optional: true - '@esbuild/android-arm@0.25.12': + '@esbuild/android-arm@0.28.1': optional: true - '@esbuild/android-x64@0.25.12': + '@esbuild/android-x64@0.28.1': optional: true - '@esbuild/darwin-arm64@0.25.12': + '@esbuild/darwin-arm64@0.28.1': optional: true - '@esbuild/darwin-x64@0.25.12': + '@esbuild/darwin-x64@0.28.1': optional: true - '@esbuild/freebsd-arm64@0.25.12': + '@esbuild/freebsd-arm64@0.28.1': optional: true - '@esbuild/freebsd-x64@0.25.12': + '@esbuild/freebsd-x64@0.28.1': optional: true - '@esbuild/linux-arm64@0.25.12': + '@esbuild/linux-arm64@0.28.1': optional: true - '@esbuild/linux-arm@0.25.12': + '@esbuild/linux-arm@0.28.1': optional: true - '@esbuild/linux-ia32@0.25.12': + '@esbuild/linux-ia32@0.28.1': optional: true - '@esbuild/linux-loong64@0.25.12': + '@esbuild/linux-loong64@0.28.1': optional: true - '@esbuild/linux-mips64el@0.25.12': + '@esbuild/linux-mips64el@0.28.1': optional: true - '@esbuild/linux-ppc64@0.25.12': + '@esbuild/linux-ppc64@0.28.1': optional: true - '@esbuild/linux-riscv64@0.25.12': + '@esbuild/linux-riscv64@0.28.1': optional: true - '@esbuild/linux-s390x@0.25.12': + '@esbuild/linux-s390x@0.28.1': optional: true - '@esbuild/linux-x64@0.25.12': + '@esbuild/linux-x64@0.28.1': optional: true - '@esbuild/netbsd-arm64@0.25.12': + '@esbuild/netbsd-arm64@0.28.1': optional: true - '@esbuild/netbsd-x64@0.25.12': + '@esbuild/netbsd-x64@0.28.1': optional: true - '@esbuild/openbsd-arm64@0.25.12': + '@esbuild/openbsd-arm64@0.28.1': optional: true - '@esbuild/openbsd-x64@0.25.12': + '@esbuild/openbsd-x64@0.28.1': optional: true - '@esbuild/openharmony-arm64@0.25.12': + '@esbuild/openharmony-arm64@0.28.1': optional: true - '@esbuild/sunos-x64@0.25.12': + '@esbuild/sunos-x64@0.28.1': optional: true - '@esbuild/win32-arm64@0.25.12': + '@esbuild/win32-arm64@0.28.1': optional: true - '@esbuild/win32-ia32@0.25.12': + '@esbuild/win32-ia32@0.28.1': optional: true - '@esbuild/win32-x64@0.25.12': + '@esbuild/win32-x64@0.28.1': optional: true '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@2.7.0))': @@ -6318,17 +6327,17 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.2 '@tailwindcss/oxide-win32-x64-msvc': 4.3.2 - '@tailwindcss/vite@4.3.2(vite@8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0))': + '@tailwindcss/vite@4.3.2(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.2 '@tailwindcss/oxide': 4.3.2 tailwindcss: 4.3.2 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0) - - '@tanstack/devtools-event-client@0.3.5': {} + vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) '@tanstack/devtools-event-client@0.4.4': {} + '@tanstack/devtools-event-client@0.5.0': {} + '@tanstack/history@1.162.0': {} '@tanstack/hotkeys@0.8.0': @@ -6671,10 +6680,10 @@ snapshots: '@typescript-eslint/types': 8.62.1 eslint-visitor-keys: 5.0.1 - '@vitejs/plugin-react@6.0.3(vite@8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0))': + '@vitejs/plugin-react@6.0.3(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) '@vitest/expect@4.1.9': dependencies: @@ -6685,13 +6694,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.9(vite@8.1.3(@types/node@26.1.0)(jiti@2.7.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.9(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.9 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) '@vitest/pretty-format@4.1.9': dependencies: @@ -7174,7 +7183,7 @@ snapshots: deep-is@0.1.4: {} - deepfilternet3-noise-filter@1.2.1(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22)): + deepfilternet3-noise-filter@1.3.0(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22)): dependencies: livekit-client: 2.20.0(@types/dom-mediacapture-record@1.0.22) @@ -7396,34 +7405,34 @@ snapshots: es6-error@4.1.1: optional: true - esbuild@0.25.12: + esbuild@0.28.1: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 + '@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: {} @@ -8725,6 +8734,26 @@ snapshots: tiny-invariant: 1.3.3 tslib: 2.8.1 + recharts@3.10.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1): + dependencies: + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7))(react@19.2.7) + clsx: 2.1.1 + decimal.js-light: 2.5.1 + es-toolkit: 1.49.0 + eventemitter3: 5.0.4 + immer: 11.1.9 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-is: 19.2.7 + react-redux: 9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1) + reselect: 5.2.0 + tiny-invariant: 1.3.3 + use-sync-external-store: 1.6.0(react@19.2.7) + victory-vendor: 37.3.6 + transitivePeerDependencies: + - '@types/react' + - redux + recharts@3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1): dependencies: '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7))(react@19.2.7) @@ -9277,7 +9306,7 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0): + vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.5 @@ -9286,15 +9315,15 @@ snapshots: tinyglobby: 0.2.17 optionalDependencies: '@types/node': 26.1.0 - esbuild: 0.25.12 + esbuild: 0.28.1 fsevents: 2.3.3 jiti: 2.7.0 yaml: 2.9.0 - vitest@4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(jiti@2.7.0)(yaml@2.9.0)): + vitest@4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.9 - '@vitest/mocker': 4.1.9(vite@8.1.3(@types/node@26.1.0)(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/mocker': 4.1.9(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.9 '@vitest/runner': 4.1.9 '@vitest/snapshot': 4.1.9 @@ -9311,7 +9340,7 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.25.12)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 26.1.0 From 2061c3c393cc7f70446488a3d3c1fae141b79d06 Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 6 Aug 2026 11:53:05 +0200 Subject: [PATCH 43/97] (feat): enable renovate --- renovate.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/renovate.json b/renovate.json index 44b87f6..6336684 100644 --- a/renovate.json +++ b/renovate.json @@ -1,5 +1,4 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "baseBranchPatterns": ["dev"], - "enabled": false + "baseBranchPatterns": ["dev"] } From 565f39c255f3e85636becc208bf0fa2a4ec81a86 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 12:02:38 +0200 Subject: [PATCH 44/97] chore(deps): update dependency reselect to v5.2.0 --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index 81fb210..3c175b1 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -111,7 +111,7 @@ "recharts": "3.10.1", "redux": "^5.0.0", "redux-thunk": "^3.1.0", - "reselect": "5.1.1", + "reselect": "5.2.0", "scheduler": "^0.27.0", "seroval": "^1.5.4", "seroval-plugins": "^1.5.4", From f3ca5d637c7f09364a1cec78565c6c78190ad9f4 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 12:02:46 +0200 Subject: [PATCH 45/97] chore(deps): update pnpm to v11.20.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2558ab8..f0bd6e8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "tensamin", "version": "0.0.11", "private": true, - "packageManager": "pnpm@11.8.0", + "packageManager": "pnpm@11.20.0", "workspaces": [ "packages/*", "apps/*" From 29e80d6d02cb0a47db05aa2bed86320d4a39fade Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 13:02:05 +0200 Subject: [PATCH 46/97] chore(deps): update rust crate jni to 0.22 --- apps/tauri/src-tauri/Cargo.lock | 2 +- apps/tauri/src-tauri/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index cacb50d..82fcc03 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -5373,7 +5373,7 @@ name = "tensamin" version = "0.0.0" dependencies = [ "base64 0.22.1", - "jni 0.21.1", + "jni 0.22.4", "mtp", "mtp-transport", "reqwest 0.12.28", diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index 1f1d4fe..6bbca97 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -37,7 +37,7 @@ features = [] default-features = true [target.'cfg(target_os = "android")'.dependencies] -jni = "0.21" +jni = "0.22" [target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] tauri-plugin-barcode-scanner = "2" From 1ea13acc3bc4a7d3f6b4d348d13ba54d896ffdaf Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 6 Aug 2026 13:49:16 +0200 Subject: [PATCH 47/97] fix(mobile): build errors --- apps/tauri/src-tauri/Cargo.lock | 2 +- apps/tauri/src-tauri/gen/android/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index 86f1b5b..f5cca9e 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -5301,7 +5301,7 @@ dependencies = [ [[package]] name = "tensamin" -version = "0.0.0" +version = "0.0.11" dependencies = [ "base64 0.22.1", "jni 0.21.1", diff --git a/apps/tauri/src-tauri/gen/android/build.gradle.kts b/apps/tauri/src-tauri/gen/android/build.gradle.kts index dddb93c..3ba890b 100644 --- a/apps/tauri/src-tauri/gen/android/build.gradle.kts +++ b/apps/tauri/src-tauri/gen/android/build.gradle.kts @@ -7,7 +7,7 @@ buildscript { } dependencies { classpath("com.android.tools.build:gradle:8.11.0") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.20") } } From 2c405af72df2c55c5568f9cf6e30d60286030b98 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Thu, 6 Aug 2026 12:19:35 +0000 Subject: [PATCH 48/97] (qol): update release flake hash --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 2d34e76..1ed0189 100644 --- a/flake.nix +++ b/flake.nix @@ -16,8 +16,8 @@ let systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; - version = "0.0.10"; - x86_64DebHash = "sha256-R7ufXBPL2+jsgtbcIjPg55RU6m39odaC5IeLI1nYU48="; + version = "0.0.11"; + x86_64DebHash = "sha256-GtPVJ+WK7np0iGA3OXTWtc7or5biFt2AkchqPRIR9Zg="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From 9ae7dbe35ea0b8c2756f398b70b8300db3184e0b Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Thu, 6 Aug 2026 12:19:37 +0000 Subject: [PATCH 49/97] (qol): update release flake hash --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 2d34e76..1ed0189 100644 --- a/flake.nix +++ b/flake.nix @@ -16,8 +16,8 @@ let systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; - version = "0.0.10"; - x86_64DebHash = "sha256-R7ufXBPL2+jsgtbcIjPg55RU6m39odaC5IeLI1nYU48="; + version = "0.0.11"; + x86_64DebHash = "sha256-GtPVJ+WK7np0iGA3OXTWtc7or5biFt2AkchqPRIR9Zg="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From 37255872323a56ca17c17ce95189c7fac2c84fa1 Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 6 Aug 2026 16:17:12 +0200 Subject: [PATCH 50/97] chore(deps): remove packageManager --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 2558ab8..9ae37ee 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "tensamin", "version": "0.0.11", "private": true, - "packageManager": "pnpm@11.8.0", "workspaces": [ "packages/*", "apps/*" From ac1bdf5ac2f6ef3f591ad3194a8cb2643f58abd5 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Thu, 6 Aug 2026 14:47:23 +0000 Subject: [PATCH 51/97] (qol): update release flake hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 1ed0189..2b8781f 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.11"; - x86_64DebHash = "sha256-GtPVJ+WK7np0iGA3OXTWtc7or5biFt2AkchqPRIR9Zg="; + x86_64DebHash = "sha256-E4FGMpCt2ByaN6d+YzglqeA6LbhMOQmPf3UzAj7uZXE="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From beafb623ba3e22daebdfa8f9cca6023f4082b962 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Thu, 6 Aug 2026 14:47:25 +0000 Subject: [PATCH 52/97] (qol): update release flake hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 1ed0189..2b8781f 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.11"; - x86_64DebHash = "sha256-GtPVJ+WK7np0iGA3OXTWtc7or5biFt2AkchqPRIR9Zg="; + x86_64DebHash = "sha256-E4FGMpCt2ByaN6d+YzglqeA6LbhMOQmPf3UzAj7uZXE="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From a731f8ee42886b4f81f7d755c44d84d325e5e948 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 19:01:31 +0200 Subject: [PATCH 53/97] chore(deps): update dependency @livekit/components-react to v2.9.23 --- pnpm-lock.yaml | 467 ++++++++++++++++++++++++------------------------- 1 file changed, 233 insertions(+), 234 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6a529ec..c4f77e0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,7 +14,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) mtp: specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz @@ -24,7 +24,7 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.6.0(jiti@2.7.0)) + version: 10.0.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0)) '@types/node': specifier: ^26.1.0 version: 26.1.0 @@ -36,13 +36,13 @@ importers: version: 19.2.3(@types/react@19.2.17) '@typescript-eslint/parser': specifier: ^8.59.1 - version: 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) + version: 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) eslint: specifier: ^10.2.1 - version: 10.6.0(jiti@2.7.0) + version: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) eslint-plugin-react-hooks: specifier: ^7.1.1 - version: 7.1.1(eslint@10.6.0(jiti@2.7.0)) + version: 7.1.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) fallow: specifier: ^2.86.0 version: 2.104.0 @@ -60,7 +60,7 @@ importers: version: 6.0.3 typescript-eslint: specifier: ^8.59.1 - version: 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) + version: 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) vitest: specifier: ^4.0.8 version: 4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) @@ -75,10 +75,10 @@ importers: version: 25.9.4 electron: specifier: ^39.2.7 - version: 39.8.10 + version: 39.8.10(supports-color@7.2.0) electron-builder: specifier: ^26.0.12 - version: 26.15.3(electron-builder-squirrel-windows@26.15.3) + version: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) esbuild: specifier: ^0.28.0 version: 0.28.1 @@ -90,7 +90,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -154,7 +154,7 @@ importers: version: 5.2.7 '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@radix-ui/primitive': specifier: ^1.1.0 version: 1.1.4 @@ -420,8 +420,8 @@ importers: specifier: ^3.1.0 version: 3.1.0(redux@5.0.1) reselect: - specifier: 5.1.1 - version: 5.1.1 + specifier: 5.2.0 + version: 5.2.0 scheduler: specifier: ^0.27.0 version: 0.27.0 @@ -433,7 +433,7 @@ importers: version: 1.5.4(seroval@1.5.4) shadcn: specifier: ^4.11.0 - version: 4.12.0(typescript@6.0.3) + version: 4.12.0(supports-color@7.2.0)(typescript@6.0.3) sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -479,7 +479,7 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.6.0(jiti@2.7.0)) + version: 10.0.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0)) '@types/qrcode': specifier: ^1.5.6 version: 1.5.6 @@ -497,7 +497,7 @@ importers: version: 0.28.1 eslint: specifier: ^10.0.3 - version: 10.6.0(jiti@2.7.0) + version: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) globals: specifier: ^17.4.0 version: 17.7.0 @@ -506,7 +506,7 @@ importers: version: 6.0.3 typescript-eslint: specifier: ^8.57.0 - version: 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) + version: 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) vite: specifier: ^8.0.10 version: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) @@ -533,10 +533,10 @@ importers: dependencies: '@livekit/components-react': specifier: ^2.9.20 - version: 2.9.21(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tslib@2.8.1) + version: 2.9.23(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tslib@2.8.1) '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.169.1 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -584,7 +584,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/pacer': specifier: ^0.21.1 version: 0.21.1 @@ -687,7 +687,7 @@ importers: version: 6.43.4 '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@twemoji/api': specifier: ^17.0.3 version: 17.0.3 @@ -705,7 +705,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -736,13 +736,13 @@ importers: devDependencies: eslint: specifier: ^10.0.3 - version: 10.6.0(jiti@2.7.0) + version: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) packages/notifications: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.169.1 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -787,7 +787,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -817,7 +817,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.169.1 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -860,7 +860,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) lucide-react: specifier: ^1.14.0 version: 1.23.0(react@19.2.7) @@ -878,7 +878,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -902,7 +902,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.0.0 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -1463,9 +1463,6 @@ packages: '@floating-ui/core@1.7.5': resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - '@floating-ui/dom@1.7.4': - resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - '@floating-ui/dom@1.7.6': resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} @@ -1554,19 +1551,19 @@ packages: '@lezer/markdown@1.6.4': resolution: {integrity: sha512-N0SxazMj4k65DBfaf1azqtMZd6u7MqluP84/NZnB/io8Td9aleFmAhz9hcbvSfsxT5tdYlJ5qgv5aMJGY4zEtA==} - '@livekit/components-core@0.12.13': - resolution: {integrity: sha512-DQmi84afHoHjZ62wm8y+XPNIDHTwFHAltjd3lmyXj8UZHOY7wcza4vFt1xnghJOD5wLRY58L1dkAgAw59MgWvw==} + '@livekit/components-core@0.12.14': + resolution: {integrity: sha512-6OKP/1Ok2fCZewDLKd3SzaTb7KvfZl/6hjggI+TgUdhp0Y7HBg3+tHA7YmhZRc0BO8wIyVy4VgTPn7qkLHt2nQ==} engines: {node: '>=18'} peerDependencies: - livekit-client: ^2.17.2 + livekit-client: ^2.20.1 tslib: ^2.6.2 - '@livekit/components-react@2.9.21': - resolution: {integrity: sha512-6hU9VucJJL+gAhilNGe4MBCDCZVk64qyjP9Ck86krvOIdVU76WeWksddg1MYUP10AlUwwrfD7davz41pJTcMJw==} + '@livekit/components-react@2.9.23': + resolution: {integrity: sha512-clO+0g/u3YBpuOvnAjUSAJBH/o7w+RpUAseswjiSML9rHrXlTUhwBNm8LPk+qN5GOU3A6lzsNnFYVpUHUBVOkg==} engines: {node: '>=18'} peerDependencies: - '@livekit/krisp-noise-filter': ^0.2.12 || ^0.3.0 - livekit-client: ^2.18.2 + '@livekit/krisp-noise-filter': ^0.2.12 || ^0.3.0 || ^0.4.0 + livekit-client: ^2.20.1 react: '>=18' react-dom: '>=18' tslib: ^2.6.2 @@ -3668,6 +3665,9 @@ packages: jose@6.2.3: resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + jose@6.2.8: + resolution: {integrity: sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -5229,20 +5229,20 @@ snapshots: '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.7': + '@babel/core@7.29.7(supports-color@7.2.0)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helpers': 7.29.7 '@babel/parser': 7.29.7 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -5269,41 +5269,41 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@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@7.2.0) '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) + '@babel/traverse': 7.29.7(supports-color@7.2.0) semver: 6.3.1 transitivePeerDependencies: - supports-color '@babel/helper-globals@7.29.7': {} - '@babel/helper-member-expression-to-functions@7.29.7': + '@babel/helper-member-expression-to-functions@7.29.7(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.29.7': + '@babel/helper-module-imports@7.29.7(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-module-imports': 7.29.7(supports-color@7.2.0) '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -5313,18 +5313,18 @@ snapshots: '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@7.2.0) '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + '@babel/helper-skip-transparent-expression-wrappers@7.29.7(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -5344,43 +5344,43 @@ snapshots: dependencies: '@babel/types': 7.29.7 - '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/preset-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-option': 7.29.7 - '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -5392,7 +5392,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/types': 7.29.7 - '@babel/traverse@7.29.7': + '@babel/traverse@7.29.7(supports-color@7.2.0)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 @@ -5400,7 +5400,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/template': 7.29.7 '@babel/types': 7.29.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -5562,46 +5562,46 @@ snapshots: fs-extra: 9.1.0 minimist: 1.2.8 - '@electron/get@2.0.3': + '@electron/get@2.0.3(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 progress: 2.0.3 semver: 6.3.1 - sumchecker: 3.0.1 + sumchecker: 3.0.1(supports-color@7.2.0) optionalDependencies: global-agent: 3.0.0 transitivePeerDependencies: - supports-color - '@electron/get@3.1.0': + '@electron/get@3.1.0(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 progress: 2.0.3 semver: 6.3.1 - sumchecker: 3.0.1 + sumchecker: 3.0.1(supports-color@7.2.0) optionalDependencies: global-agent: 3.0.0 transitivePeerDependencies: - supports-color - '@electron/notarize@2.5.0': + '@electron/notarize@2.5.0(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 9.1.0 promise-retry: 2.0.1 transitivePeerDependencies: - supports-color - '@electron/osx-sign@1.3.3': + '@electron/osx-sign@1.3.3(supports-color@7.2.0)': dependencies: compare-version: 0.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 10.1.0 isbinaryfile: 4.0.10 minimist: 1.2.8 @@ -5609,22 +5609,22 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/rebuild@4.2.0': + '@electron/rebuild@4.2.0(supports-color@7.2.0)': dependencies: '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) node-abi: 4.33.0 node-api-version: 0.2.1 node-gyp: 12.4.0 - read-binary-file-arch: 1.0.6 + read-binary-file-arch: 1.0.6(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@electron/universal@2.0.3': + '@electron/universal@2.0.3(supports-color@7.2.0)': dependencies: '@electron/asar': 3.4.1 '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) dir-compare: 4.2.0 fs-extra: 11.4.0 minimatch: 9.0.9 @@ -5632,10 +5632,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/windows-sign@1.2.2': + '@electron/windows-sign@1.2.2(supports-color@7.2.0)': dependencies: cross-dirname: 0.1.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 11.4.0 minimist: 1.2.8 postject: 1.0.0-alpha.6 @@ -5737,17 +5737,17 @@ snapshots: '@esbuild/win32-x64@0.28.1': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@2.7.0))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))': dependencies: - eslint: 10.6.0(jiti@2.7.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.23.5': + '@eslint/config-array@0.23.5(supports-color@7.2.0)': dependencies: '@eslint/object-schema': 3.0.5 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) minimatch: 10.2.5 transitivePeerDependencies: - supports-color @@ -5760,9 +5760,9 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.6.0(jiti@2.7.0))': + '@eslint/js@10.0.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))': optionalDependencies: - eslint: 10.6.0(jiti@2.7.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) '@eslint/object-schema@3.0.5': {} @@ -5799,11 +5799,6 @@ snapshots: dependencies: '@floating-ui/utils': 0.2.11 - '@floating-ui/dom@1.7.4': - dependencies: - '@floating-ui/core': 1.7.5 - '@floating-ui/utils': 0.2.11 - '@floating-ui/dom@1.7.6': dependencies: '@floating-ui/core': 1.7.5 @@ -5899,20 +5894,20 @@ snapshots: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@livekit/components-core@0.12.13(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22))(tslib@2.8.1)': + '@livekit/components-core@0.12.14(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22))(tslib@2.8.1)': dependencies: - '@floating-ui/dom': 1.7.4 + '@floating-ui/dom': 1.7.6 livekit-client: 2.20.0(@types/dom-mediacapture-record@1.0.22) loglevel: 1.9.1 rxjs: 7.8.2 tslib: 2.8.1 - '@livekit/components-react@2.9.21(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tslib@2.8.1)': + '@livekit/components-react@2.9.23(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tslib@2.8.1)': dependencies: - '@livekit/components-core': 0.12.13(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22))(tslib@2.8.1) + '@livekit/components-core': 0.12.14(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22))(tslib@2.8.1) clsx: 2.1.1 events: 3.3.0 - jose: 6.2.3 + jose: 6.2.8 livekit-client: 2.20.0(@types/dom-mediacapture-record@1.0.22) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -5929,9 +5924,9 @@ snapshots: dependencies: cross-spawn: 7.0.6 - '@malept/flatpak-bundler@0.4.0': + '@malept/flatpak-bundler@0.4.0(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 9.1.0 lodash: 4.18.1 tmp-promise: 3.0.3 @@ -5940,7 +5935,7 @@ snapshots: '@marijn/find-cluster-break@1.0.3': {} - '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3)': + '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@base-ui/react': 1.6.0(@date-fns/tz@1.5.0)(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tauri-apps/api': 2.11.1 @@ -5955,7 +5950,7 @@ snapshots: react-dom: 19.2.7(react@19.2.7) react-resizable-panels: 4.12.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) recharts: 3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1) - shadcn: 4.12.0(typescript@6.0.3) + shadcn: 4.12.0(supports-color@7.2.0)(typescript@6.0.3) sonner: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) tailwind-merge: 3.6.0 tw-animate-css: 1.4.0 @@ -5972,7 +5967,7 @@ snapshots: - supports-color - typescript - '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.29.0(supports-color@7.2.0)(zod@3.25.76)': dependencies: '@hono/node-server': 1.19.14(hono@4.12.27) ajv: 8.20.0 @@ -5982,8 +5977,8 @@ snapshots: cross-spawn: 7.0.6 eventsource: 3.0.7 eventsource-parser: 3.1.0 - express: 5.2.1 - express-rate-limit: 8.5.2(express@5.2.1) + express: 5.2.1(supports-color@7.2.0) + express-rate-limit: 8.5.2(express@5.2.1(supports-color@7.2.0)) hono: 4.12.27 jose: 6.2.3 json-schema-typed: 8.0.2 @@ -6196,7 +6191,7 @@ snapshots: immer: 11.1.9 redux: 5.0.1 redux-thunk: 3.1.0(redux@5.0.1) - reselect: 5.1.1 + reselect: 5.2.0 optionalDependencies: react: 19.2.7 react-redux: 9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1) @@ -6589,15 +6584,15 @@ snapshots: '@types/node': 25.9.4 optional: true - '@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.62.1 - '@typescript-eslint/type-utils': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/type-utils': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.62.1 - eslint: 10.6.0(jiti@2.7.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -6605,23 +6600,23 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.62.1 '@typescript-eslint/types': 8.62.1 - '@typescript-eslint/typescript-estree': 8.62.1(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.62.1(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.62.1 - debug: 4.4.3 - eslint: 10.6.0(jiti@2.7.0) + debug: 4.4.3(supports-color@7.2.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.62.1(typescript@6.0.3)': + '@typescript-eslint/project-service@8.62.1(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.62.1(typescript@6.0.3) '@typescript-eslint/types': 8.62.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -6635,13 +6630,13 @@ snapshots: dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.62.1 - '@typescript-eslint/typescript-estree': 8.62.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) - debug: 4.4.3 - eslint: 10.6.0(jiti@2.7.0) + '@typescript-eslint/typescript-estree': 8.62.1(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + debug: 4.4.3(supports-color@7.2.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: @@ -6649,13 +6644,13 @@ snapshots: '@typescript-eslint/types@8.62.1': {} - '@typescript-eslint/typescript-estree@8.62.1(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.62.1(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.62.1(typescript@6.0.3) + '@typescript-eslint/project-service': 8.62.1(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/tsconfig-utils': 8.62.1(typescript@6.0.3) '@typescript-eslint/types': 8.62.1 '@typescript-eslint/visitor-keys': 8.62.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) minimatch: 10.2.5 semver: 7.8.5 tinyglobby: 0.2.17 @@ -6664,13 +6659,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/utils@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0)) '@typescript-eslint/scope-manager': 8.62.1 '@typescript-eslint/types': 8.62.1 - '@typescript-eslint/typescript-estree': 8.62.1(typescript@6.0.3) - eslint: 10.6.0(jiti@2.7.0) + '@typescript-eslint/typescript-estree': 8.62.1(supports-color@7.2.0)(typescript@6.0.3) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -6775,33 +6770,33 @@ snapshots: dependencies: color-convert: 2.0.1 - app-builder-lib@26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3): + app-builder-lib@26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): dependencies: '@electron/asar': 3.4.1 '@electron/fuses': 1.8.0 - '@electron/get': 3.1.0 - '@electron/notarize': 2.5.0 - '@electron/osx-sign': 1.3.3 - '@electron/rebuild': 4.2.0 - '@electron/universal': 2.0.3 - '@malept/flatpak-bundler': 0.4.0 + '@electron/get': 3.1.0(supports-color@7.2.0) + '@electron/notarize': 2.5.0(supports-color@7.2.0) + '@electron/osx-sign': 1.3.3(supports-color@7.2.0) + '@electron/rebuild': 4.2.0(supports-color@7.2.0) + '@electron/universal': 2.0.3(supports-color@7.2.0) + '@malept/flatpak-bundler': 0.4.0(supports-color@7.2.0) '@noble/hashes': 2.2.0 '@peculiar/webcrypto': 1.7.1 '@types/fs-extra': 9.0.13 ajv: 8.20.0 asn1js: 3.0.10 async-exit-hook: 2.0.1 - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chromium-pickle-js: 0.2.0 ci-info: 4.3.1 - debug: 4.4.3 - dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) + debug: 4.4.3(supports-color@7.2.0) + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) dotenv: 16.6.1 dotenv-expand: 11.0.7 ejs: 3.1.10 - electron-builder-squirrel-windows: 26.15.3(dmg-builder@26.15.3) - electron-publish: 26.15.3 + electron-builder-squirrel-windows: 26.15.3(dmg-builder@26.15.3)(supports-color@7.2.0) + electron-publish: 26.15.3(supports-color@7.2.0) fs-extra: 10.1.0 hosted-git-info: 4.1.0 isbinaryfile: 5.0.7 @@ -6865,11 +6860,11 @@ snapshots: bluebird@3.7.2: {} - body-parser@2.3.0: + body-parser@2.3.0(supports-color@7.2.0): dependencies: bytes: 3.1.2 content-type: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 @@ -6919,23 +6914,23 @@ snapshots: buffer-from@1.1.2: {} - builder-util-runtime@9.7.0: + builder-util-runtime@9.7.0(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) sax: 1.6.0 transitivePeerDependencies: - supports-color - builder-util@26.15.3: + builder-util@26.15.3(supports-color@7.2.0): dependencies: '@types/debug': 4.1.13 - builder-util-runtime: 9.7.0 + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 10.1.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + http-proxy-agent: 7.0.2(supports-color@7.2.0) + https-proxy-agent: 7.0.6(supports-color@7.2.0) js-yaml: 4.3.0 sanitize-filename: 1.6.4 source-map-support: 0.5.21 @@ -7167,9 +7162,11 @@ snapshots: dependencies: mimic-fn: 3.1.0 - debug@4.4.3: + debug@4.4.3(supports-color@7.2.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 7.2.0 decamelize@1.2.0: {} @@ -7236,10 +7233,10 @@ snapshots: minimatch: 3.1.5 p-limit: 3.1.0 - dmg-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): + dmg-builder@26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) fs-extra: 10.1.0 js-yaml: 4.3.0 transitivePeerDependencies: @@ -7274,23 +7271,23 @@ snapshots: dependencies: jake: 10.9.4 - electron-builder-squirrel-windows@26.15.3(dmg-builder@26.15.3): + electron-builder-squirrel-windows@26.15.3(dmg-builder@26.15.3)(supports-color@7.2.0): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 - electron-winstaller: 5.4.0 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) + electron-winstaller: 5.4.0(supports-color@7.2.0) transitivePeerDependencies: - dmg-builder - supports-color - electron-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): + electron-builder@26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 ci-info: 4.4.0 - dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) fs-extra: 10.1.0 lazy-val: 1.0.5 simple-update-notifier: 2.0.0 @@ -7299,12 +7296,12 @@ snapshots: - electron-builder-squirrel-windows - supports-color - electron-publish@26.15.3: + electron-publish@26.15.3(supports-color@7.2.0): dependencies: '@types/fs-extra': 9.0.13 aws4: 1.13.2 - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 form-data: 4.0.6 fs-extra: 10.1.0 @@ -7317,23 +7314,23 @@ snapshots: electron-to-chromium@1.5.396: {} - electron-winstaller@5.4.0: + electron-winstaller@5.4.0(supports-color@7.2.0): dependencies: '@electron/asar': 3.4.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 7.0.1 lodash: 4.18.1 temp: 0.9.4 optionalDependencies: - '@electron/windows-sign': 1.2.2 + '@electron/windows-sign': 1.2.2(supports-color@7.2.0) transitivePeerDependencies: - supports-color - electron@39.8.10: + electron@39.8.10(supports-color@7.2.0): dependencies: - '@electron/get': 2.0.3 + '@electron/get': 2.0.3(supports-color@7.2.0) '@types/node': 22.20.0 - extract-zip: 2.0.1 + extract-zip: 2.0.1(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -7440,11 +7437,11 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-react-hooks@7.1.1(eslint@10.6.0(jiti@2.7.0)): + eslint-plugin-react-hooks@7.1.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/parser': 7.29.7 - eslint: 10.6.0(jiti@2.7.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) hermes-parser: 0.25.1 zod: 4.4.3 zod-validation-error: 4.0.2(zod@4.4.3) @@ -7462,11 +7459,11 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.6.0(jiti@2.7.0): + eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.5 + '@eslint/config-array': 0.23.5(supports-color@7.2.0) '@eslint/config-helpers': 0.6.0 '@eslint/core': 1.2.1 '@eslint/plugin-kit': 0.7.2 @@ -7476,7 +7473,7 @@ snapshots: '@types/estree': 1.0.9 ajv: 6.15.0 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) escape-string-regexp: 4.0.0 eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 @@ -7566,25 +7563,25 @@ snapshots: exponential-backoff@3.1.3: {} - express-rate-limit@8.5.2(express@5.2.1): + express-rate-limit@8.5.2(express@5.2.1(supports-color@7.2.0)): dependencies: - express: 5.2.1 + express: 5.2.1(supports-color@7.2.0) ip-address: 10.2.0 - express@5.2.1: + express@5.2.1(supports-color@7.2.0): dependencies: accepts: 2.0.0 - body-parser: 2.3.0 + body-parser: 2.3.0(supports-color@7.2.0) content-disposition: 1.1.0 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 2.1.1 + finalhandler: 2.1.1(supports-color@7.2.0) fresh: 2.0.0 http-errors: 2.0.1 merge-descriptors: 2.0.0 @@ -7595,18 +7592,18 @@ snapshots: proxy-addr: 2.0.7 qs: 6.15.3 range-parser: 1.3.0 - router: 2.2.0 - send: 1.2.1 - serve-static: 2.2.1 + router: 2.2.0(supports-color@7.2.0) + send: 1.2.1(supports-color@7.2.0) + serve-static: 2.2.1(supports-color@7.2.0) statuses: 2.0.2 type-is: 2.1.0 vary: 1.1.2 transitivePeerDependencies: - supports-color - extract-zip@2.0.1: + extract-zip@2.0.1(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -7671,9 +7668,9 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.1: + finalhandler@2.1.1(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -7907,10 +7904,10 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 - http-proxy-agent@7.0.2: + http-proxy-agent@7.0.2(supports-color@7.2.0): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -7919,10 +7916,10 @@ snapshots: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - https-proxy-agent@7.0.6: + https-proxy-agent@7.0.6(supports-color@7.2.0): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -8041,6 +8038,8 @@ snapshots: jose@6.2.3: {} + jose@6.2.8: {} + js-tokens@4.0.0: {} js-yaml@4.3.0: @@ -8710,9 +8709,9 @@ snapshots: react@19.2.7: {} - read-binary-file-arch@1.0.6: + read-binary-file-arch@1.0.6(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -8846,9 +8845,9 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.1.5 '@rolldown/binding-win32-x64-msvc': 1.1.5 - router@2.2.0: + router@2.2.0(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -8893,9 +8892,9 @@ snapshots: semver@7.8.5: {} - send@1.2.1: + send@1.2.1(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -8920,12 +8919,12 @@ snapshots: seroval@1.5.4: {} - serve-static@2.2.1: + serve-static@2.2.1(supports-color@7.2.0): dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 1.2.1 + send: 1.2.1(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -8933,14 +8932,14 @@ snapshots: setprototypeof@1.2.0: {} - shadcn@4.12.0(typescript@6.0.3): + shadcn@4.12.0(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/parser': 7.29.7 - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) - '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@dotenvx/dotenvx': 1.75.1 - '@modelcontextprotocol/sdk': 1.29.0(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.29.0(supports-color@7.2.0)(zod@3.25.76) '@types/validate-npm-package-name': 4.0.2 browserslist: 4.28.4 commander: 14.0.3 @@ -9084,9 +9083,9 @@ snapshots: style-mod@4.1.3: {} - sumchecker@3.0.1: + sumchecker@3.0.1(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -9193,13 +9192,13 @@ snapshots: optionalDependencies: rxjs: 7.8.2 - typescript-eslint@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3): + typescript-eslint@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.62.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) - eslint: 10.6.0(jiti@2.7.0) + '@typescript-eslint/eslint-plugin': 8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.62.1(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color From 35769b1aae4cf7ba1c43dc2323b3701d5b3ba033 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 20:01:22 +0200 Subject: [PATCH 54/97] chore(deps): update dependency @codemirror/lang-markdown to v6.5.1 --- pnpm-lock.yaml | 497 +++++++++++++++++++++++++------------------------ 1 file changed, 258 insertions(+), 239 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6a529ec..7090d27 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,7 +14,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) mtp: specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz @@ -24,7 +24,7 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.6.0(jiti@2.7.0)) + version: 10.0.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0)) '@types/node': specifier: ^26.1.0 version: 26.1.0 @@ -36,13 +36,13 @@ importers: version: 19.2.3(@types/react@19.2.17) '@typescript-eslint/parser': specifier: ^8.59.1 - version: 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) + version: 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) eslint: specifier: ^10.2.1 - version: 10.6.0(jiti@2.7.0) + version: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) eslint-plugin-react-hooks: specifier: ^7.1.1 - version: 7.1.1(eslint@10.6.0(jiti@2.7.0)) + version: 7.1.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) fallow: specifier: ^2.86.0 version: 2.104.0 @@ -60,7 +60,7 @@ importers: version: 6.0.3 typescript-eslint: specifier: ^8.59.1 - version: 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) + version: 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) vitest: specifier: ^4.0.8 version: 4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) @@ -75,10 +75,10 @@ importers: version: 25.9.4 electron: specifier: ^39.2.7 - version: 39.8.10 + version: 39.8.10(supports-color@7.2.0) electron-builder: specifier: ^26.0.12 - version: 26.15.3(electron-builder-squirrel-windows@26.15.3) + version: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) esbuild: specifier: ^0.28.0 version: 0.28.1 @@ -90,7 +90,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -154,7 +154,7 @@ importers: version: 5.2.7 '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@radix-ui/primitive': specifier: ^1.1.0 version: 1.1.4 @@ -420,8 +420,8 @@ importers: specifier: ^3.1.0 version: 3.1.0(redux@5.0.1) reselect: - specifier: 5.1.1 - version: 5.1.1 + specifier: 5.2.0 + version: 5.2.0 scheduler: specifier: ^0.27.0 version: 0.27.0 @@ -433,7 +433,7 @@ importers: version: 1.5.4(seroval@1.5.4) shadcn: specifier: ^4.11.0 - version: 4.12.0(typescript@6.0.3) + version: 4.12.0(supports-color@7.2.0)(typescript@6.0.3) sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -479,7 +479,7 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.6.0(jiti@2.7.0)) + version: 10.0.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0)) '@types/qrcode': specifier: ^1.5.6 version: 1.5.6 @@ -497,7 +497,7 @@ importers: version: 0.28.1 eslint: specifier: ^10.0.3 - version: 10.6.0(jiti@2.7.0) + version: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) globals: specifier: ^17.4.0 version: 17.7.0 @@ -506,7 +506,7 @@ importers: version: 6.0.3 typescript-eslint: specifier: ^8.57.0 - version: 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) + version: 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) vite: specifier: ^8.0.10 version: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) @@ -536,7 +536,7 @@ importers: version: 2.9.21(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tslib@2.8.1) '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.169.1 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -584,7 +584,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/pacer': specifier: ^0.21.1 version: 0.21.1 @@ -675,7 +675,7 @@ importers: version: 6.10.4 '@codemirror/lang-markdown': specifier: ^6.5.0 - version: 6.5.0 + version: 6.5.1 '@codemirror/language': specifier: ^6.12.4 version: 6.12.4 @@ -687,7 +687,7 @@ importers: version: 6.43.4 '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@twemoji/api': specifier: ^17.0.3 version: 17.0.3 @@ -705,7 +705,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -736,13 +736,13 @@ importers: devDependencies: eslint: specifier: ^10.0.3 - version: 10.6.0(jiti@2.7.0) + version: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) packages/notifications: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.169.1 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -787,7 +787,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -817,7 +817,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.169.1 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -860,7 +860,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) lucide-react: specifier: ^1.14.0 version: 1.23.0(react@19.2.7) @@ -878,7 +878,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -902,7 +902,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.0.0 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -1145,14 +1145,14 @@ packages: '@codemirror/lang-css@6.3.1': resolution: {integrity: sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==} - '@codemirror/lang-html@6.4.11': - resolution: {integrity: sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==} + '@codemirror/lang-html@6.4.12': + resolution: {integrity: sha512-pw2ReWKUqSkbvh76RAT4NYxiogRu+PWkR2ukAwO9uOgrm8uipkzjtKKtNpyeAQwHOqxEeSvAXZ6vr3AfyB9y/w==} '@codemirror/lang-javascript@6.2.5': resolution: {integrity: sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==} - '@codemirror/lang-markdown@6.5.0': - resolution: {integrity: sha512-0K40bZ35jpHya6FriukbgaleaqzBLZfOh7HuzqbMxBXkbYMJDxfF39c23xOgxFezR+3G+tR2/Mup+Xk865OMvw==} + '@codemirror/lang-markdown@6.5.1': + resolution: {integrity: sha512-6re5avCNfyRMIoi3XNjbEfQM1vTeVD3JS3g/Fyegyso/eoANFM71Cyvbb66LDyYtQLMEcRFlzioywCqDo9SlLA==} '@codemirror/language@6.12.4': resolution: {integrity: sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==} @@ -1163,9 +1163,15 @@ packages: '@codemirror/state@6.7.0': resolution: {integrity: sha512-Zbl9NyscLMZkfXPQnNAIIAFftidrA1UbcJEIMp24C0Bukc2I5T8wJS0wsXYsnDOqCFJUeJ1BITGNs5CqPDSmSg==} + '@codemirror/state@6.7.1': + resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==} + '@codemirror/view@6.43.4': resolution: {integrity: sha512-YImu23iyKfncJzT7sRy+rEqEhSc8RhOHqDxwy4WzXRKJwYm6iwf/9OJk5ctCAdZ6yi2ZqaGEvmf55fSVqMDrgg==} + '@codemirror/view@6.43.8': + resolution: {integrity: sha512-qtItTDssZ/5GFfi94hrILu9j/VUeFPDPkhovEfmWFj2ipTxnzPB8DdHgfbb8HYTzLTYhrndKmyQxXUz/PDLenw==} + '@date-fns/tz@1.5.0': resolution: {integrity: sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==} @@ -1536,8 +1542,8 @@ packages: '@lezer/common@1.5.2': resolution: {integrity: sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==} - '@lezer/css@1.3.4': - resolution: {integrity: sha512-N+tn9tej2hPvyKgHEApMOQfHczDJCwxrRFS3SPn9QjYN+uwHvEDnCgKRrb3mxDYxRS8sKMM8fhC3+lc04Abz5Q==} + '@lezer/css@1.3.6': + resolution: {integrity: sha512-YJE78Wcg+zX8f10hiHWQ4Az48Qr/c13eId0VtRQYLBpxHDmDeSrXIlkbl+fJGW42rWC/uoUco9mhBZeVWP/A1g==} '@lezer/highlight@1.2.3': resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} @@ -1551,8 +1557,8 @@ packages: '@lezer/lr@1.4.10': resolution: {integrity: sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==} - '@lezer/markdown@1.6.4': - resolution: {integrity: sha512-N0SxazMj4k65DBfaf1azqtMZd6u7MqluP84/NZnB/io8Td9aleFmAhz9hcbvSfsxT5tdYlJ5qgv5aMJGY4zEtA==} + '@lezer/markdown@1.7.2': + resolution: {integrity: sha512-iTkYvoVcKt3WkeL7qUDyXHONZEwLio4wj8KTNi2dnjQEXBZKMV63BpQrPqfsM+OkvuRbiSTAcycYAsQzLhRNoQ==} '@livekit/components-core@0.12.13': resolution: {integrity: sha512-DQmi84afHoHjZ62wm8y+XPNIDHTwFHAltjd3lmyXj8UZHOY7wcza4vFt1xnghJOD5wLRY58L1dkAgAw59MgWvw==} @@ -5229,20 +5235,20 @@ snapshots: '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.7': + '@babel/core@7.29.7(supports-color@7.2.0)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 '@babel/helper-compilation-targets': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helpers': 7.29.7 '@babel/parser': 7.29.7 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -5269,41 +5275,41 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@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@7.2.0) '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) + '@babel/traverse': 7.29.7(supports-color@7.2.0) semver: 6.3.1 transitivePeerDependencies: - supports-color '@babel/helper-globals@7.29.7': {} - '@babel/helper-member-expression-to-functions@7.29.7': + '@babel/helper-member-expression-to-functions@7.29.7(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.29.7': + '@babel/helper-module-imports@7.29.7(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-module-imports': 7.29.7(supports-color@7.2.0) '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -5313,18 +5319,18 @@ snapshots: '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@7.2.0) '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + '@babel/helper-skip-transparent-expression-wrappers@7.29.7(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.7(supports-color@7.2.0) '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -5344,43 +5350,43 @@ snapshots: dependencies: '@babel/types': 7.29.7 - '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/preset-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-option': 7.29.7 - '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -5392,7 +5398,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/types': 7.29.7 - '@babel/traverse@7.29.7': + '@babel/traverse@7.29.7(supports-color@7.2.0)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.7 @@ -5400,7 +5406,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/template': 7.29.7 '@babel/types': 7.29.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -5465,20 +5471,20 @@ snapshots: dependencies: '@codemirror/autocomplete': 6.20.3 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 '@lezer/common': 1.5.2 - '@lezer/css': 1.3.4 + '@lezer/css': 1.3.6 - '@codemirror/lang-html@6.4.11': + '@codemirror/lang-html@6.4.12': dependencies: '@codemirror/autocomplete': 6.20.3 '@codemirror/lang-css': 6.3.1 '@codemirror/lang-javascript': 6.2.5 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.8 '@lezer/common': 1.5.2 - '@lezer/css': 1.3.4 + '@lezer/css': 1.3.6 '@lezer/html': 1.3.13 '@codemirror/lang-javascript@6.2.5': @@ -5486,20 +5492,20 @@ snapshots: '@codemirror/autocomplete': 6.20.3 '@codemirror/language': 6.12.4 '@codemirror/lint': 6.9.7 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.8 '@lezer/common': 1.5.2 '@lezer/javascript': 1.5.4 - '@codemirror/lang-markdown@6.5.0': + '@codemirror/lang-markdown@6.5.1': dependencies: '@codemirror/autocomplete': 6.20.3 - '@codemirror/lang-html': 6.4.11 + '@codemirror/lang-html': 6.4.12 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.8 '@lezer/common': 1.5.2 - '@lezer/markdown': 1.6.4 + '@lezer/markdown': 1.7.2 '@codemirror/language@6.12.4': dependencies: @@ -5512,14 +5518,18 @@ snapshots: '@codemirror/lint@6.9.7': dependencies: - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.8 crelt: 1.0.7 '@codemirror/state@6.7.0': dependencies: '@marijn/find-cluster-break': 1.0.3 + '@codemirror/state@6.7.1': + dependencies: + '@marijn/find-cluster-break': 1.0.3 + '@codemirror/view@6.43.4': dependencies: '@codemirror/state': 6.7.0 @@ -5527,6 +5537,13 @@ snapshots: style-mod: 4.1.3 w3c-keyname: 2.2.8 + '@codemirror/view@6.43.8': + dependencies: + '@codemirror/state': 6.7.1 + crelt: 1.0.7 + style-mod: 4.1.3 + w3c-keyname: 2.2.8 + '@date-fns/tz@1.5.0': {} '@dotenvx/dotenvx@1.75.1': @@ -5562,46 +5579,46 @@ snapshots: fs-extra: 9.1.0 minimist: 1.2.8 - '@electron/get@2.0.3': + '@electron/get@2.0.3(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 progress: 2.0.3 semver: 6.3.1 - sumchecker: 3.0.1 + sumchecker: 3.0.1(supports-color@7.2.0) optionalDependencies: global-agent: 3.0.0 transitivePeerDependencies: - supports-color - '@electron/get@3.1.0': + '@electron/get@3.1.0(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 progress: 2.0.3 semver: 6.3.1 - sumchecker: 3.0.1 + sumchecker: 3.0.1(supports-color@7.2.0) optionalDependencies: global-agent: 3.0.0 transitivePeerDependencies: - supports-color - '@electron/notarize@2.5.0': + '@electron/notarize@2.5.0(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 9.1.0 promise-retry: 2.0.1 transitivePeerDependencies: - supports-color - '@electron/osx-sign@1.3.3': + '@electron/osx-sign@1.3.3(supports-color@7.2.0)': dependencies: compare-version: 0.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 10.1.0 isbinaryfile: 4.0.10 minimist: 1.2.8 @@ -5609,22 +5626,22 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/rebuild@4.2.0': + '@electron/rebuild@4.2.0(supports-color@7.2.0)': dependencies: '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) node-abi: 4.33.0 node-api-version: 0.2.1 node-gyp: 12.4.0 - read-binary-file-arch: 1.0.6 + read-binary-file-arch: 1.0.6(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@electron/universal@2.0.3': + '@electron/universal@2.0.3(supports-color@7.2.0)': dependencies: '@electron/asar': 3.4.1 '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) dir-compare: 4.2.0 fs-extra: 11.4.0 minimatch: 9.0.9 @@ -5632,10 +5649,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/windows-sign@1.2.2': + '@electron/windows-sign@1.2.2(supports-color@7.2.0)': dependencies: cross-dirname: 0.1.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 11.4.0 minimist: 1.2.8 postject: 1.0.0-alpha.6 @@ -5737,17 +5754,17 @@ snapshots: '@esbuild/win32-x64@0.28.1': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@2.7.0))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))': dependencies: - eslint: 10.6.0(jiti@2.7.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.23.5': + '@eslint/config-array@0.23.5(supports-color@7.2.0)': dependencies: '@eslint/object-schema': 3.0.5 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) minimatch: 10.2.5 transitivePeerDependencies: - supports-color @@ -5760,9 +5777,9 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.6.0(jiti@2.7.0))': + '@eslint/js@10.0.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))': optionalDependencies: - eslint: 10.6.0(jiti@2.7.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) '@eslint/object-schema@3.0.5': {} @@ -5868,7 +5885,7 @@ snapshots: '@lezer/common@1.5.2': {} - '@lezer/css@1.3.4': + '@lezer/css@1.3.6': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 @@ -5894,7 +5911,7 @@ snapshots: dependencies: '@lezer/common': 1.5.2 - '@lezer/markdown@1.6.4': + '@lezer/markdown@1.7.2': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 @@ -5929,9 +5946,9 @@ snapshots: dependencies: cross-spawn: 7.0.6 - '@malept/flatpak-bundler@0.4.0': + '@malept/flatpak-bundler@0.4.0(supports-color@7.2.0)': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 9.1.0 lodash: 4.18.1 tmp-promise: 3.0.3 @@ -5940,7 +5957,7 @@ snapshots: '@marijn/find-cluster-break@1.0.3': {} - '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(typescript@6.0.3)': + '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@base-ui/react': 1.6.0(@date-fns/tz@1.5.0)(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tauri-apps/api': 2.11.1 @@ -5955,7 +5972,7 @@ snapshots: react-dom: 19.2.7(react@19.2.7) react-resizable-panels: 4.12.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) recharts: 3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1) - shadcn: 4.12.0(typescript@6.0.3) + shadcn: 4.12.0(supports-color@7.2.0)(typescript@6.0.3) sonner: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) tailwind-merge: 3.6.0 tw-animate-css: 1.4.0 @@ -5972,7 +5989,7 @@ snapshots: - supports-color - typescript - '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.29.0(supports-color@7.2.0)(zod@3.25.76)': dependencies: '@hono/node-server': 1.19.14(hono@4.12.27) ajv: 8.20.0 @@ -5982,8 +5999,8 @@ snapshots: cross-spawn: 7.0.6 eventsource: 3.0.7 eventsource-parser: 3.1.0 - express: 5.2.1 - express-rate-limit: 8.5.2(express@5.2.1) + express: 5.2.1(supports-color@7.2.0) + express-rate-limit: 8.5.2(express@5.2.1(supports-color@7.2.0)) hono: 4.12.27 jose: 6.2.3 json-schema-typed: 8.0.2 @@ -6196,7 +6213,7 @@ snapshots: immer: 11.1.9 redux: 5.0.1 redux-thunk: 3.1.0(redux@5.0.1) - reselect: 5.1.1 + reselect: 5.2.0 optionalDependencies: react: 19.2.7 react-redux: 9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1) @@ -6589,15 +6606,15 @@ snapshots: '@types/node': 25.9.4 optional: true - '@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.62.1 - '@typescript-eslint/type-utils': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/type-utils': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.62.1 - eslint: 10.6.0(jiti@2.7.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -6605,23 +6622,23 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.62.1 '@typescript-eslint/types': 8.62.1 - '@typescript-eslint/typescript-estree': 8.62.1(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.62.1(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.62.1 - debug: 4.4.3 - eslint: 10.6.0(jiti@2.7.0) + debug: 4.4.3(supports-color@7.2.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.62.1(typescript@6.0.3)': + '@typescript-eslint/project-service@8.62.1(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.62.1(typescript@6.0.3) '@typescript-eslint/types': 8.62.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -6635,13 +6652,13 @@ snapshots: dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.62.1 - '@typescript-eslint/typescript-estree': 8.62.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) - debug: 4.4.3 - eslint: 10.6.0(jiti@2.7.0) + '@typescript-eslint/typescript-estree': 8.62.1(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + debug: 4.4.3(supports-color@7.2.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: @@ -6649,13 +6666,13 @@ snapshots: '@typescript-eslint/types@8.62.1': {} - '@typescript-eslint/typescript-estree@8.62.1(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.62.1(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.62.1(typescript@6.0.3) + '@typescript-eslint/project-service': 8.62.1(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/tsconfig-utils': 8.62.1(typescript@6.0.3) '@typescript-eslint/types': 8.62.1 '@typescript-eslint/visitor-keys': 8.62.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) minimatch: 10.2.5 semver: 7.8.5 tinyglobby: 0.2.17 @@ -6664,13 +6681,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/utils@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0)) '@typescript-eslint/scope-manager': 8.62.1 '@typescript-eslint/types': 8.62.1 - '@typescript-eslint/typescript-estree': 8.62.1(typescript@6.0.3) - eslint: 10.6.0(jiti@2.7.0) + '@typescript-eslint/typescript-estree': 8.62.1(supports-color@7.2.0)(typescript@6.0.3) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -6775,33 +6792,33 @@ snapshots: dependencies: color-convert: 2.0.1 - app-builder-lib@26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3): + app-builder-lib@26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): dependencies: '@electron/asar': 3.4.1 '@electron/fuses': 1.8.0 - '@electron/get': 3.1.0 - '@electron/notarize': 2.5.0 - '@electron/osx-sign': 1.3.3 - '@electron/rebuild': 4.2.0 - '@electron/universal': 2.0.3 - '@malept/flatpak-bundler': 0.4.0 + '@electron/get': 3.1.0(supports-color@7.2.0) + '@electron/notarize': 2.5.0(supports-color@7.2.0) + '@electron/osx-sign': 1.3.3(supports-color@7.2.0) + '@electron/rebuild': 4.2.0(supports-color@7.2.0) + '@electron/universal': 2.0.3(supports-color@7.2.0) + '@malept/flatpak-bundler': 0.4.0(supports-color@7.2.0) '@noble/hashes': 2.2.0 '@peculiar/webcrypto': 1.7.1 '@types/fs-extra': 9.0.13 ajv: 8.20.0 asn1js: 3.0.10 async-exit-hook: 2.0.1 - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chromium-pickle-js: 0.2.0 ci-info: 4.3.1 - debug: 4.4.3 - dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) + debug: 4.4.3(supports-color@7.2.0) + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) dotenv: 16.6.1 dotenv-expand: 11.0.7 ejs: 3.1.10 - electron-builder-squirrel-windows: 26.15.3(dmg-builder@26.15.3) - electron-publish: 26.15.3 + electron-builder-squirrel-windows: 26.15.3(dmg-builder@26.15.3)(supports-color@7.2.0) + electron-publish: 26.15.3(supports-color@7.2.0) fs-extra: 10.1.0 hosted-git-info: 4.1.0 isbinaryfile: 5.0.7 @@ -6865,11 +6882,11 @@ snapshots: bluebird@3.7.2: {} - body-parser@2.3.0: + body-parser@2.3.0(supports-color@7.2.0): dependencies: bytes: 3.1.2 content-type: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 @@ -6919,23 +6936,23 @@ snapshots: buffer-from@1.1.2: {} - builder-util-runtime@9.7.0: + builder-util-runtime@9.7.0(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) sax: 1.6.0 transitivePeerDependencies: - supports-color - builder-util@26.15.3: + builder-util@26.15.3(supports-color@7.2.0): dependencies: '@types/debug': 4.1.13 - builder-util-runtime: 9.7.0 + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 10.1.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + http-proxy-agent: 7.0.2(supports-color@7.2.0) + https-proxy-agent: 7.0.6(supports-color@7.2.0) js-yaml: 4.3.0 sanitize-filename: 1.6.4 source-map-support: 0.5.21 @@ -7167,9 +7184,11 @@ snapshots: dependencies: mimic-fn: 3.1.0 - debug@4.4.3: + debug@4.4.3(supports-color@7.2.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 7.2.0 decamelize@1.2.0: {} @@ -7236,10 +7255,10 @@ snapshots: minimatch: 3.1.5 p-limit: 3.1.0 - dmg-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): + dmg-builder@26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) fs-extra: 10.1.0 js-yaml: 4.3.0 transitivePeerDependencies: @@ -7274,23 +7293,23 @@ snapshots: dependencies: jake: 10.9.4 - electron-builder-squirrel-windows@26.15.3(dmg-builder@26.15.3): + electron-builder-squirrel-windows@26.15.3(dmg-builder@26.15.3)(supports-color@7.2.0): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 - electron-winstaller: 5.4.0 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) + electron-winstaller: 5.4.0(supports-color@7.2.0) transitivePeerDependencies: - dmg-builder - supports-color - electron-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): + electron-builder@26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 ci-info: 4.4.0 - dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) fs-extra: 10.1.0 lazy-val: 1.0.5 simple-update-notifier: 2.0.0 @@ -7299,12 +7318,12 @@ snapshots: - electron-builder-squirrel-windows - supports-color - electron-publish@26.15.3: + electron-publish@26.15.3(supports-color@7.2.0): dependencies: '@types/fs-extra': 9.0.13 aws4: 1.13.2 - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 form-data: 4.0.6 fs-extra: 10.1.0 @@ -7317,23 +7336,23 @@ snapshots: electron-to-chromium@1.5.396: {} - electron-winstaller@5.4.0: + electron-winstaller@5.4.0(supports-color@7.2.0): dependencies: '@electron/asar': 3.4.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) fs-extra: 7.0.1 lodash: 4.18.1 temp: 0.9.4 optionalDependencies: - '@electron/windows-sign': 1.2.2 + '@electron/windows-sign': 1.2.2(supports-color@7.2.0) transitivePeerDependencies: - supports-color - electron@39.8.10: + electron@39.8.10(supports-color@7.2.0): dependencies: - '@electron/get': 2.0.3 + '@electron/get': 2.0.3(supports-color@7.2.0) '@types/node': 22.20.0 - extract-zip: 2.0.1 + extract-zip: 2.0.1(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -7440,11 +7459,11 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-react-hooks@7.1.1(eslint@10.6.0(jiti@2.7.0)): + eslint-plugin-react-hooks@7.1.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/parser': 7.29.7 - eslint: 10.6.0(jiti@2.7.0) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) hermes-parser: 0.25.1 zod: 4.4.3 zod-validation-error: 4.0.2(zod@4.4.3) @@ -7462,11 +7481,11 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.6.0(jiti@2.7.0): + eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.5 + '@eslint/config-array': 0.23.5(supports-color@7.2.0) '@eslint/config-helpers': 0.6.0 '@eslint/core': 1.2.1 '@eslint/plugin-kit': 0.7.2 @@ -7476,7 +7495,7 @@ snapshots: '@types/estree': 1.0.9 ajv: 6.15.0 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) escape-string-regexp: 4.0.0 eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 @@ -7566,25 +7585,25 @@ snapshots: exponential-backoff@3.1.3: {} - express-rate-limit@8.5.2(express@5.2.1): + express-rate-limit@8.5.2(express@5.2.1(supports-color@7.2.0)): dependencies: - express: 5.2.1 + express: 5.2.1(supports-color@7.2.0) ip-address: 10.2.0 - express@5.2.1: + express@5.2.1(supports-color@7.2.0): dependencies: accepts: 2.0.0 - body-parser: 2.3.0 + body-parser: 2.3.0(supports-color@7.2.0) content-disposition: 1.1.0 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 2.1.1 + finalhandler: 2.1.1(supports-color@7.2.0) fresh: 2.0.0 http-errors: 2.0.1 merge-descriptors: 2.0.0 @@ -7595,18 +7614,18 @@ snapshots: proxy-addr: 2.0.7 qs: 6.15.3 range-parser: 1.3.0 - router: 2.2.0 - send: 1.2.1 - serve-static: 2.2.1 + router: 2.2.0(supports-color@7.2.0) + send: 1.2.1(supports-color@7.2.0) + serve-static: 2.2.1(supports-color@7.2.0) statuses: 2.0.2 type-is: 2.1.0 vary: 1.1.2 transitivePeerDependencies: - supports-color - extract-zip@2.0.1: + extract-zip@2.0.1(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -7671,9 +7690,9 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.1: + finalhandler@2.1.1(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -7907,10 +7926,10 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 - http-proxy-agent@7.0.2: + http-proxy-agent@7.0.2(supports-color@7.2.0): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -7919,10 +7938,10 @@ snapshots: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - https-proxy-agent@7.0.6: + https-proxy-agent@7.0.6(supports-color@7.2.0): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -8710,9 +8729,9 @@ snapshots: react@19.2.7: {} - read-binary-file-arch@1.0.6: + read-binary-file-arch@1.0.6(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -8846,9 +8865,9 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.1.5 '@rolldown/binding-win32-x64-msvc': 1.1.5 - router@2.2.0: + router@2.2.0(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -8893,9 +8912,9 @@ snapshots: semver@7.8.5: {} - send@1.2.1: + send@1.2.1(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -8920,12 +8939,12 @@ snapshots: seroval@1.5.4: {} - serve-static@2.2.1: + serve-static@2.2.1(supports-color@7.2.0): dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 1.2.1 + send: 1.2.1(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -8933,14 +8952,14 @@ snapshots: setprototypeof@1.2.0: {} - shadcn@4.12.0(typescript@6.0.3): + shadcn@4.12.0(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/parser': 7.29.7 - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) - '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@dotenvx/dotenvx': 1.75.1 - '@modelcontextprotocol/sdk': 1.29.0(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.29.0(supports-color@7.2.0)(zod@3.25.76) '@types/validate-npm-package-name': 4.0.2 browserslist: 4.28.4 commander: 14.0.3 @@ -9084,9 +9103,9 @@ snapshots: style-mod@4.1.3: {} - sumchecker@3.0.1: + sumchecker@3.0.1(supports-color@7.2.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -9193,13 +9212,13 @@ snapshots: optionalDependencies: rxjs: 7.8.2 - typescript-eslint@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3): + typescript-eslint@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.62.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@6.0.3) - eslint: 10.6.0(jiti@2.7.0) + '@typescript-eslint/eslint-plugin': 8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.62.1(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color From dfb82373c69bcc67dfda39a103b1528847da3bdd Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 21:00:43 +0200 Subject: [PATCH 55/97] chore(deps): update dependency @codemirror/state to v6.7.1 --- pnpm-lock.yaml | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4ae5dbb..10e3c32 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -681,7 +681,7 @@ importers: version: 6.12.4 '@codemirror/state': specifier: ^6.5.4 - version: 6.7.0 + version: 6.7.1 '@codemirror/view': specifier: ^6.41.1 version: 6.43.4 @@ -1160,9 +1160,6 @@ packages: '@codemirror/lint@6.9.7': resolution: {integrity: sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==} - '@codemirror/state@6.7.0': - resolution: {integrity: sha512-Zbl9NyscLMZkfXPQnNAIIAFftidrA1UbcJEIMp24C0Bukc2I5T8wJS0wsXYsnDOqCFJUeJ1BITGNs5CqPDSmSg==} - '@codemirror/state@6.7.1': resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==} @@ -5456,14 +5453,14 @@ snapshots: '@codemirror/autocomplete@6.20.3': dependencies: '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 '@codemirror/view': 6.43.4 '@lezer/common': 1.5.2 '@codemirror/commands@6.10.4': dependencies: '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 '@codemirror/view': 6.43.4 '@lezer/common': 1.5.2 @@ -5509,7 +5506,7 @@ snapshots: '@codemirror/language@6.12.4': dependencies: - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 '@codemirror/view': 6.43.4 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 @@ -5522,17 +5519,13 @@ snapshots: '@codemirror/view': 6.43.8 crelt: 1.0.7 - '@codemirror/state@6.7.0': - dependencies: - '@marijn/find-cluster-break': 1.0.3 - '@codemirror/state@6.7.1': dependencies: '@marijn/find-cluster-break': 1.0.3 '@codemirror/view@6.43.4': dependencies: - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 crelt: 1.0.7 style-mod: 4.1.3 w3c-keyname: 2.2.8 From 3954d776cefc0c1ab5fb78012189b7f310ffef50 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 6 Aug 2026 22:00:39 +0200 Subject: [PATCH 56/97] chore(deps): update dependency @codemirror/view to v6.43.6 --- pnpm-lock.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10e3c32..1f0f82b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -684,7 +684,7 @@ importers: version: 6.7.1 '@codemirror/view': specifier: ^6.41.1 - version: 6.43.4 + version: 6.43.6 '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) @@ -1163,8 +1163,8 @@ packages: '@codemirror/state@6.7.1': resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==} - '@codemirror/view@6.43.4': - resolution: {integrity: sha512-YImu23iyKfncJzT7sRy+rEqEhSc8RhOHqDxwy4WzXRKJwYm6iwf/9OJk5ctCAdZ6yi2ZqaGEvmf55fSVqMDrgg==} + '@codemirror/view@6.43.6': + resolution: {integrity: sha512-EVunGSYN1wz1p75WY1s3Xg7t3i8Yol0kGZGizNdX9BUFgMFILYVe8/u6EVpo7Ff5PwbZuILb4QAq7IZoKzIEQA==} '@codemirror/view@6.43.8': resolution: {integrity: sha512-qtItTDssZ/5GFfi94hrILu9j/VUeFPDPkhovEfmWFj2ipTxnzPB8DdHgfbb8HYTzLTYhrndKmyQxXUz/PDLenw==} @@ -5454,14 +5454,14 @@ snapshots: dependencies: '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.4 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@codemirror/commands@6.10.4': dependencies: '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.4 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@codemirror/lang-css@6.3.1': @@ -5507,7 +5507,7 @@ snapshots: '@codemirror/language@6.12.4': dependencies: '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.4 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.10 @@ -5523,7 +5523,7 @@ snapshots: dependencies: '@marijn/find-cluster-break': 1.0.3 - '@codemirror/view@6.43.4': + '@codemirror/view@6.43.6': dependencies: '@codemirror/state': 6.7.1 crelt: 1.0.7 From b76143e2e2f2488671729dc5ac590e8c2ae3e78c Mon Sep 17 00:00:00 2001 From: Alois Date: Fri, 7 Aug 2026 21:51:35 +0200 Subject: [PATCH 57/97] chore(deps): update everything --- package.json | 22 +- pnpm-lock.yaml | 1273 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 1105 insertions(+), 190 deletions(-) diff --git a/package.json b/package.json index 9ae37ee..7f0738e 100644 --- a/package.json +++ b/package.json @@ -29,19 +29,19 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@types/node": "^26.1.0", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@typescript-eslint/parser": "^8.59.1", - "eslint": "^10.2.1", + "@types/node": "^26.1.2", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.4", + "@typescript-eslint/parser": "^8.66.0", + "eslint": "^10.8.0", "eslint-plugin-react-hooks": "^7.1.1", - "fallow": "^2.86.0", - "globals": "^17.5.0", + "fallow": "^3.14.0", + "globals": "^17.9.0", "jsonc-parser": "^3.3.1", - "prettier": "^3.8.3", - "typescript": "^6.0.3", - "typescript-eslint": "^8.59.1", - "vitest": "^4.0.8", + "prettier": "^3.9.6", + "typescript": "^7.0.2", + "typescript-eslint": "^8.66.0", + "vitest": "^4.1.10", "yaml": "^2.8.2" }, "dependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1f0f82b..68b2e43 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,7 +14,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2) mtp: specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz @@ -24,46 +24,46 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0)) + version: 10.0.1(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0)) '@types/node': - specifier: ^26.1.0 - version: 26.1.0 + specifier: ^26.1.2 + version: 26.1.2 '@types/react': - specifier: ^19.2.14 - version: 19.2.17 + specifier: ^19.2.18 + version: 19.2.18 '@types/react-dom': - specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.17) + specifier: ^19.2.4 + version: 19.2.4(@types/react@19.2.18) '@typescript-eslint/parser': - specifier: ^8.59.1 - version: 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + specifier: ^8.66.0 + version: 8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2) eslint: - specifier: ^10.2.1 - version: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) + specifier: ^10.8.0 + version: 10.8.0(jiti@2.7.0)(supports-color@7.2.0) eslint-plugin-react-hooks: specifier: ^7.1.1 - version: 7.1.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) + version: 7.1.1(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) fallow: - specifier: ^2.86.0 - version: 2.104.0 + specifier: ^3.14.0 + version: 3.14.0 globals: - specifier: ^17.5.0 - version: 17.7.0 + specifier: ^17.9.0 + version: 17.9.0 jsonc-parser: specifier: ^3.3.1 version: 3.3.1 prettier: - specifier: ^3.8.3 - version: 3.9.4 + specifier: ^3.9.6 + version: 3.9.6 typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 typescript-eslint: - specifier: ^8.59.1 - version: 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + specifier: ^8.66.0 + version: 8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2) vitest: - specifier: ^4.0.8 - version: 4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) + specifier: ^4.1.10 + version: 4.1.10(@types/node@26.1.2)(vite@8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) yaml: specifier: ^2.8.2 version: 2.9.0 @@ -90,7 +90,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -205,10 +205,10 @@ importers: version: 1.1.2(@types/react@19.2.17)(react@19.2.7) '@reduxjs/toolkit': specifier: ^2.0.0 - version: 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7))(react@19.2.7) + version: 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1))(react@19.2.7) '@tailwindcss/vite': specifier: ^4.2.4 - version: 4.3.2(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.3.2(vite@8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) '@tanstack/devtools-event-client': specifier: ^0.5.0 version: 0.5.0 @@ -491,7 +491,7 @@ importers: version: 19.2.3(@types/react@19.2.17) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.3(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) + version: 6.0.3(vite@8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) esbuild: specifier: ^0.28.0 version: 0.28.1 @@ -509,7 +509,7 @@ importers: version: 8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) vite: specifier: ^8.0.10 - version: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + version: 8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) packages/cache: dependencies: @@ -536,7 +536,7 @@ importers: version: 2.9.23(livekit-client@2.20.0(@types/dom-mediacapture-record@1.0.22))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tslib@2.8.1) '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@7.0.2) '@tanstack/react-router': specifier: ^1.169.1 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -572,7 +572,7 @@ importers: version: 19.2.7(react@19.2.7) recharts: specifier: ^3.8.1 - version: 3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1) + version: 3.8.1(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1) zod: specifier: ^4.3.6 version: 4.4.3 @@ -584,7 +584,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2) '@tanstack/pacer': specifier: ^0.21.1 version: 0.21.1 @@ -663,7 +663,7 @@ importers: devDependencies: vite: specifier: ^8.0.10 - version: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + version: 8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) packages/markdown: dependencies: @@ -687,7 +687,7 @@ importers: version: 6.43.6 '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2) '@twemoji/api': specifier: ^17.0.3 version: 17.0.3 @@ -705,7 +705,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -742,7 +742,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2) '@tanstack/react-router': specifier: ^1.169.1 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -787,7 +787,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -817,7 +817,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2) '@tanstack/react-router': specifier: ^1.169.1 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -854,13 +854,13 @@ importers: devDependencies: vite: specifier: ^8.0.10 - version: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + version: 8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) packages/shared: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2) lucide-react: specifier: ^1.14.0 version: 1.23.0(react@19.2.7) @@ -878,7 +878,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2) '@tauri-apps/api': specifier: ^2 version: 2.11.1 @@ -902,7 +902,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2) '@tanstack/react-router': specifier: ^1.0.0 version: 1.170.17(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -1384,6 +1384,12 @@ packages: cpu: [x64] os: [win32] + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1402,6 +1408,10 @@ packages: resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@eslint/config-helpers@0.7.0': + resolution: {integrity: sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@eslint/core@1.2.1': resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -1423,43 +1433,43 @@ packages: resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@fallow-cli/darwin-arm64@2.104.0': - resolution: {integrity: sha512-5kKt3JuoYVz5/9PpHdu8u41vOZ6CzIu+5SqNBR8MktGLVMBSERm85+NN63XqgbZrVwIC/5uiP8eHQ0RYw0qhHg==} + '@fallow-cli/darwin-arm64@3.14.0': + resolution: {integrity: sha512-seaix3OqADcq90PkPOOPrN8Jl7QZDGjFziHA85Ikp+lGSHVjJ2IMyGh/QKLhvi9Q6Ha3Y//F0+PFFGNd0Gi4mw==} cpu: [arm64] os: [darwin] - '@fallow-cli/darwin-x64@2.104.0': - resolution: {integrity: sha512-BEwwYccutb8RxyAm3uE8vwCJ3JSLYYeREj3fpLPFFCjh9eXBBo3Q1Mu5pxBjjUeehfbR6r/FLJb9JV28bCia9g==} + '@fallow-cli/darwin-x64@3.14.0': + resolution: {integrity: sha512-qgYZHHTFobuJCtON7aVe/tXCUjiF/9nKT4tNLVfUPH4Qe9KwieO4rAuknDOnxkjzsWPO4MfHyCbcVdslf4JMnw==} cpu: [x64] os: [darwin] - '@fallow-cli/linux-arm64-gnu@2.104.0': - resolution: {integrity: sha512-IyIkmwxm0AfVKXfHYuSBO6Fzt6fgZsRE0arbtObeDlKSv7zZMzqHZPpbSGZxPEmVODBMScdSxxaFSli9xFHBTA==} + '@fallow-cli/linux-arm64-gnu@3.14.0': + resolution: {integrity: sha512-FwmIG391lMViBXh1cAvOcwQxbI2sLjEYkugFauVbmntjuJt6xVxQXAxjybdFXSL/jjfFnbAzPKy9oHlhq3sA6A==} cpu: [arm64] os: [linux] - '@fallow-cli/linux-arm64-musl@2.104.0': - resolution: {integrity: sha512-YskAeLCUUPnbwqtMC452ksI+miw6hN4K6peTFRJ0j2gSpkTriJfUgkudFB1+JX2/YqV41yDAqe5XeDYhuXxjOA==} + '@fallow-cli/linux-arm64-musl@3.14.0': + resolution: {integrity: sha512-x4R9aNT2kIoSHRIZ5s2MZ+swyb3uutV6SSYCwWhPSE5UI/oCEYWNWiYS7uKMLM0cTuMPVcsm2qMTd4iYA3ACLw==} cpu: [arm64] os: [linux] - '@fallow-cli/linux-x64-gnu@2.104.0': - resolution: {integrity: sha512-v3Um0fXwTPg7kGRD1hKeS36A7P/3J7h3TiQ2KAzE8ThKkDViHYjKGEkajtGGSIj/Tv+GVnJBOvJ7i752/6iSBA==} + '@fallow-cli/linux-x64-gnu@3.14.0': + resolution: {integrity: sha512-8kBxy9FkwKjiH1C19T0nSkmbtldwVyWLQWajIqvyHE0x4rurHhve7RQrwEDPzNMFu7OgYCMU1nXr/AMIJ6Kg9w==} cpu: [x64] os: [linux] - '@fallow-cli/linux-x64-musl@2.104.0': - resolution: {integrity: sha512-wMVyeSp5uHvzVUgNHk6xuTCisVOAUv8FTC6z1swANdLQlQgd4Trnu8GYwhJhO7cU9RuL85yn1XksCs6+PkRM8A==} + '@fallow-cli/linux-x64-musl@3.14.0': + resolution: {integrity: sha512-9TAdXSpYvk9WkKy2GR8T/PHbq7QCTO/SYUmiZ+EAJUMzXBvSfnpj8cCGQpeAD000Nb+o7rL94lIAPJMAqMKO3Q==} cpu: [x64] os: [linux] - '@fallow-cli/win32-arm64-msvc@2.104.0': - resolution: {integrity: sha512-qDRn7zoRKVAHVz+BqKUnUPa8H4gD/g26Fs/hqH9futbthecgjXmPyRJwycE8HTQBNlVwck5d5w36a+PEPsCYaQ==} + '@fallow-cli/win32-arm64-msvc@3.14.0': + resolution: {integrity: sha512-xc495cracyJL+0UKwcqNhofIz2K5XiJbb+YFhxrbSrrbm+EVDnQKpCOzzOJYbm7RPxF6XOxJpATn7ciBy7Rqrw==} cpu: [arm64] os: [win32] - '@fallow-cli/win32-x64-msvc@2.104.0': - resolution: {integrity: sha512-irER9HuZ9DXunl4H9RNsWQ9AvGmHs/Zp1+Yr2ATmgSNumERPXvgXa2IiGtCvKFqI72639TlhUj8+2WqIXZ54WQ==} + '@fallow-cli/win32-x64-msvc@3.14.0': + resolution: {integrity: sha512-ihyCZ5GMoYGnzlPP6b5pZBBcGZhDHDW2u1YEGkZEuf3pbW6E45U7Hhf213cE2CCheScXOirK6AKWnLM/Qj4c2A==} cpu: [x64] os: [win32] @@ -2305,6 +2315,9 @@ packages: '@types/node@26.1.0': resolution: {integrity: sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw==} + '@types/node@26.1.2': + resolution: {integrity: sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==} + '@types/qrcode@1.5.6': resolution: {integrity: sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==} @@ -2313,9 +2326,17 @@ packages: peerDependencies: '@types/react': ^19.2.0 + '@types/react-dom@19.2.4': + resolution: {integrity: sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==} + peerDependencies: + '@types/react': ^19.2.0 + '@types/react@19.2.17': resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} + '@types/react@19.2.18': + resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} + '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} @@ -2336,6 +2357,14 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/eslint-plugin@8.66.0': + resolution: {integrity: sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.66.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/parser@8.62.1': resolution: {integrity: sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2343,22 +2372,45 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/parser@8.66.0': + resolution: {integrity: sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/project-service@8.62.1': resolution: {integrity: sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/project-service@8.66.0': + resolution: {integrity: sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/scope-manager@8.62.1': resolution: {integrity: sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.66.0': + resolution: {integrity: sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/tsconfig-utils@8.62.1': resolution: {integrity: sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/tsconfig-utils@8.66.0': + resolution: {integrity: sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/type-utils@8.62.1': resolution: {integrity: sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2366,16 +2418,33 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/type-utils@8.66.0': + resolution: {integrity: sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/types@8.62.1': resolution: {integrity: sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.66.0': + resolution: {integrity: sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.62.1': resolution: {integrity: sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/typescript-estree@8.66.0': + resolution: {integrity: sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/utils@8.62.1': resolution: {integrity: sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2383,10 +2452,141 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/utils@8.66.0': + resolution: {integrity: sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/visitor-keys@8.62.1': resolution: {integrity: sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.66.0': + resolution: {integrity: sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] + + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] + + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] + + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] + + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] + + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + '@vitejs/plugin-react@6.0.3': resolution: {integrity: sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2400,11 +2600,11 @@ packages: babel-plugin-react-compiler: optional: true - '@vitest/expect@4.1.9': - resolution: {integrity: sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==} + '@vitest/expect@4.1.10': + resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} - '@vitest/mocker@4.1.9': - resolution: {integrity: sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==} + '@vitest/mocker@4.1.10': + resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2414,20 +2614,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.9': - resolution: {integrity: sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==} + '@vitest/pretty-format@4.1.10': + resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} - '@vitest/runner@4.1.9': - resolution: {integrity: sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==} + '@vitest/runner@4.1.10': + resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} - '@vitest/snapshot@4.1.9': - resolution: {integrity: sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==} + '@vitest/snapshot@4.1.10': + resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} - '@vitest/spy@4.1.9': - resolution: {integrity: sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==} + '@vitest/spy@4.1.10': + resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} - '@vitest/utils@4.1.9': - resolution: {integrity: sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==} + '@vitest/utils@4.1.10': + resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} @@ -2446,8 +2646,8 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.17.0: - resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} engines: {node: '>=0.4.0'} hasBin: true @@ -2581,6 +2781,10 @@ packages: resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} engines: {node: 18 || 20 || >=22} + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + engines: {node: 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -3079,8 +3283,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@2.3.0: - resolution: {integrity: sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==} + es-module-lexer@2.3.1: + resolution: {integrity: sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==} es-object-atoms@1.1.2: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} @@ -3140,6 +3344,16 @@ packages: jiti: optional: true + eslint@10.8.0: + resolution: {integrity: sha512-nuKKvN+oIBO0koN7Tm7dlkmnkc21mtt0QJLwAKzjLq14y6lRTdVG36MZHJ8eQHwdJMwZbQNMlPOYedMq/oVJvQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + espree@11.2.0: resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -3217,9 +3431,14 @@ packages: engines: {node: '>= 10.17.0'} hasBin: true - fallow@2.104.0: - resolution: {integrity: sha512-UX6Q10Feyb7epe5tTI0sHCHPReOhuKOtxdVpkbqr1lLSZirv2PJiLTTrJr7gKeLHbztE9CHR1y7YARSe0rNYag==} - engines: {node: '>=16'} + fallow-type-aware@3.14.0: + resolution: {integrity: sha512-D8+bNELjmoVV2dKpmHplQ1YzuheHltmZKaOVJ//hx7h8vFNyp5H3hcJV8rR26ofBU51z9K5eyA7FpgP3hebjwg==} + engines: {node: '>=20'} + hasBin: true + + fallow@3.14.0: + resolution: {integrity: sha512-hse+sChmWkrffLiZDPGdNSyiLybVEhgoiYCIYgqLwdYhfTCO+f2PS1g+gMhGAJdLlYpZ75tFwRoMBFmZjN3Q6g==} + engines: {node: '>=22'} hasBin: true fast-deep-equal@3.1.3: @@ -3288,8 +3507,8 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} form-data@4.0.6: resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} @@ -3419,6 +3638,10 @@ packages: resolution: {integrity: sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==} engines: {node: '>=18'} + globals@17.9.0: + resolution: {integrity: sha512-m/MvAW61QVU5VDNF1Vj8axt016h8w7L5TU1e9zlab7XIttAT2YAlCwl75K1fOqvMM9apmD7lbCIRhpfkhmxhCg==} + engines: {node: '>=18'} + globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -3506,6 +3729,10 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} + ignore@7.0.6: + resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} + engines: {node: '>= 4'} + immer@10.2.0: resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==} @@ -4019,6 +4246,10 @@ packages: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} @@ -4151,8 +4382,8 @@ packages: resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==} engines: {node: '>= 10'} - obug@2.1.3: - resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} + obug@2.1.4: + resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} engines: {node: '>=12.20.0'} on-finished@2.4.1: @@ -4322,8 +4553,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.9.4: - resolution: {integrity: sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==} + prettier@3.9.6: + resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} engines: {node: '>=14'} hasBin: true @@ -4720,8 +4951,8 @@ packages: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} - std-env@4.1.0: - resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + std-env@4.2.0: + resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} stdin-discarder@0.2.2: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} @@ -4814,16 +5045,16 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@1.2.4: - resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + tinyexec@1.3.0: + resolution: {integrity: sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==} engines: {node: '>=18'} tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} - tinyrainbow@3.1.0: - resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + tinyrainbow@3.1.1: + resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} engines: {node: '>=14.0.0'} tmp-promise@3.0.3: @@ -4885,11 +5116,23 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + typescript-eslint@8.66.0: + resolution: {integrity: sha512-QlEbBPz/RuJ1XUHj29nm3t0F/O/cSlEnntozqPOYHnnTGAXFamnMBu5i9Vn6vhUPHGAjR+Vl+5J8vPN/BMUrJw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} + engines: {node: '>=16.20.0'} + hasBin: true + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -5032,20 +5275,20 @@ packages: yaml: optional: true - vitest@4.1.9: - resolution: {integrity: sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==} + vitest@4.1.10: + resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.9 - '@vitest/browser-preview': 4.1.9 - '@vitest/browser-webdriverio': 4.1.9 - '@vitest/coverage-istanbul': 4.1.9 - '@vitest/coverage-v8': 4.1.9 - '@vitest/ui': 4.1.9 + '@vitest/browser-playwright': 4.1.10 + '@vitest/browser-preview': 4.1.10 + '@vitest/browser-webdriverio': 4.1.10 + '@vitest/coverage-istanbul': 4.1.10 + '@vitest/coverage-v8': 4.1.10 + '@vitest/ui': 4.1.10 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -5426,6 +5669,20 @@ snapshots: '@types/react': 19.2.17 date-fns: 4.4.0 + '@base-ui/react@1.6.0(@date-fns/tz@1.5.0)(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@babel/runtime': 7.29.7 + '@base-ui/utils': 0.3.1(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@floating-ui/utils': 0.2.11 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + use-sync-external-store: 1.6.0(react@19.2.7) + optionalDependencies: + '@date-fns/tz': 1.5.0 + '@types/react': 19.2.18 + date-fns: 4.4.0 + '@base-ui/utils@0.3.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@babel/runtime': 7.29.7 @@ -5437,6 +5694,17 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + '@base-ui/utils@0.3.1(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@babel/runtime': 7.29.7 + '@floating-ui/utils': 0.2.11 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + reselect: 5.2.0 + use-sync-external-store: 1.6.0(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.18 + '@base-ui/utils@0.3.2(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@babel/runtime': 7.29.7 @@ -5747,6 +6015,11 @@ snapshots: '@esbuild/win32-x64@0.28.1': optional: true + '@eslint-community/eslint-utils@4.10.1(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))': + dependencies: + eslint: 10.8.0(jiti@2.7.0)(supports-color@7.2.0) + eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))': dependencies: eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) @@ -5758,7 +6031,7 @@ snapshots: dependencies: '@eslint/object-schema': 3.0.5 debug: 4.4.3(supports-color@7.2.0) - minimatch: 10.2.5 + minimatch: 10.2.6 transitivePeerDependencies: - supports-color @@ -5766,6 +6039,10 @@ snapshots: dependencies: '@eslint/core': 1.2.1 + '@eslint/config-helpers@0.7.0': + dependencies: + '@eslint/core': 1.2.1 + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 @@ -5774,6 +6051,10 @@ snapshots: optionalDependencies: eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) + '@eslint/js@10.0.1(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))': + optionalDependencies: + eslint: 10.8.0(jiti@2.7.0)(supports-color@7.2.0) + '@eslint/object-schema@3.0.5': {} '@eslint/plugin-kit@0.7.2': @@ -5781,28 +6062,28 @@ snapshots: '@eslint/core': 1.2.1 levn: 0.4.1 - '@fallow-cli/darwin-arm64@2.104.0': + '@fallow-cli/darwin-arm64@3.14.0': optional: true - '@fallow-cli/darwin-x64@2.104.0': + '@fallow-cli/darwin-x64@3.14.0': optional: true - '@fallow-cli/linux-arm64-gnu@2.104.0': + '@fallow-cli/linux-arm64-gnu@3.14.0': optional: true - '@fallow-cli/linux-arm64-musl@2.104.0': + '@fallow-cli/linux-arm64-musl@3.14.0': optional: true - '@fallow-cli/linux-x64-gnu@2.104.0': + '@fallow-cli/linux-x64-gnu@3.14.0': optional: true - '@fallow-cli/linux-x64-musl@2.104.0': + '@fallow-cli/linux-x64-musl@3.14.0': optional: true - '@fallow-cli/win32-arm64-msvc@2.104.0': + '@fallow-cli/win32-arm64-msvc@3.14.0': optional: true - '@fallow-cli/win32-x64-msvc@2.104.0': + '@fallow-cli/win32-x64-msvc@3.14.0': optional: true '@floating-ui/core@1.7.5': @@ -5977,6 +6258,70 @@ snapshots: - supports-color - typescript + '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)(supports-color@7.2.0)(typescript@7.0.2)': + dependencies: + '@base-ui/react': 1.6.0(@date-fns/tz@1.5.0)(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@tauri-apps/api': 2.11.1 + class-variance-authority: 0.7.1 + clsx: 2.1.1 + cmdk: 1.1.1(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + embla-carousel-react: 8.6.0(react@19.2.7) + input-otp: 1.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + lucide-react: 1.23.0(react@19.2.7) + next-themes: 0.4.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-resizable-panels: 4.12.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + recharts: 3.8.1(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1) + shadcn: 4.12.0(supports-color@7.2.0)(typescript@7.0.2) + sonner: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + tailwind-merge: 3.6.0 + tw-animate-css: 1.4.0 + vaul: 1.1.2(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + transitivePeerDependencies: + - '@cfworker/json-schema' + - '@date-fns/tz' + - '@types/react' + - '@types/react-dom' + - babel-plugin-macros + - date-fns + - react-is + - redux + - supports-color + - typescript + + '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@date-fns/tz@1.5.0)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(supports-color@7.2.0)(typescript@7.0.2)': + dependencies: + '@base-ui/react': 1.6.0(@date-fns/tz@1.5.0)(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@tauri-apps/api': 2.11.1 + class-variance-authority: 0.7.1 + clsx: 2.1.1 + cmdk: 1.1.1(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + embla-carousel-react: 8.6.0(react@19.2.7) + input-otp: 1.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + lucide-react: 1.23.0(react@19.2.7) + next-themes: 0.4.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-resizable-panels: 4.12.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + recharts: 3.8.1(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7) + shadcn: 4.12.0(supports-color@7.2.0)(typescript@7.0.2) + sonner: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + tailwind-merge: 3.6.0 + tw-animate-css: 1.4.0 + vaul: 1.1.2(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + transitivePeerDependencies: + - '@cfworker/json-schema' + - '@date-fns/tz' + - '@types/react' + - '@types/react-dom' + - babel-plugin-macros + - date-fns + - react-is + - redux + - supports-color + - typescript + '@modelcontextprotocol/sdk@1.29.0(supports-color@7.2.0)(zod@3.25.76)': dependencies: '@hono/node-server': 1.19.14(hono@4.12.27) @@ -6054,12 +6399,24 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + '@radix-ui/react-compose-refs@1.1.3(@types/react@19.2.18)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.18 + '@radix-ui/react-context@1.1.4(@types/react@19.2.17)(react@19.2.7)': dependencies: react: 19.2.7 optionalDependencies: '@types/react': 19.2.17 + '@radix-ui/react-context@1.1.4(@types/react@19.2.18)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.18 + '@radix-ui/react-dialog@1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 @@ -6082,6 +6439,28 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@radix-ui/react-dialog@1.1.18(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.18)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.18)(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.18)(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.18)(react@19.2.7) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.18)(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.18)(react@19.2.7) + aria-hidden: 1.2.6 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-remove-scroll: 2.7.2(@types/react@19.2.18)(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@radix-ui/react-dismissable-layer@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 @@ -6095,12 +6474,31 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@radix-ui/react-dismissable-layer@1.1.14(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.18)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.18)(react@19.2.7) + '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.18)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@radix-ui/react-focus-guards@1.1.4(@types/react@19.2.17)(react@19.2.7)': dependencies: react: 19.2.7 optionalDependencies: '@types/react': 19.2.17 + '@radix-ui/react-focus-guards@1.1.4(@types/react@19.2.18)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.18 + '@radix-ui/react-focus-scope@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) @@ -6112,6 +6510,17 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@radix-ui/react-focus-scope@1.1.11(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.18)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.18)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@radix-ui/react-id@1.1.2(@types/react@19.2.17)(react@19.2.7)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -6119,6 +6528,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + '@radix-ui/react-id@1.1.2(@types/react@19.2.18)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.18)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.18 + '@radix-ui/react-portal@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -6129,6 +6545,16 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@radix-ui/react-portal@1.1.13(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.18)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@radix-ui/react-presence@1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -6138,6 +6564,15 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@radix-ui/react-presence@1.1.6(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.18)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@radix-ui/react-primitive@2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) @@ -6147,6 +6582,15 @@ snapshots: '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@radix-ui/react-primitive@2.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.18)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) + '@radix-ui/react-slot@1.3.0(@types/react@19.2.17)(react@19.2.7)': dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) @@ -6154,12 +6598,25 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + '@radix-ui/react-slot@1.3.0(@types/react@19.2.18)(react@19.2.7)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.18)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.18 + '@radix-ui/react-use-callback-ref@1.1.2(@types/react@19.2.17)(react@19.2.7)': dependencies: react: 19.2.7 optionalDependencies: '@types/react': 19.2.17 + '@radix-ui/react-use-callback-ref@1.1.2(@types/react@19.2.18)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.18 + '@radix-ui/react-use-controllable-state@1.2.3(@types/react@19.2.17)(react@19.2.7)': dependencies: '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) @@ -6168,6 +6625,14 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + '@radix-ui/react-use-controllable-state@1.2.3(@types/react@19.2.18)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.18)(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.18)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.18 + '@radix-ui/react-use-effect-event@0.0.3(@types/react@19.2.17)(react@19.2.7)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -6175,6 +6640,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + '@radix-ui/react-use-effect-event@0.0.3(@types/react@19.2.18)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.18)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.18 + '@radix-ui/react-use-effect-event@0.0.5(@types/react@19.2.17)(react@19.2.7)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.2.17)(react@19.2.7) @@ -6188,13 +6660,19 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + '@radix-ui/react-use-layout-effect@1.1.2(@types/react@19.2.18)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.18 + '@radix-ui/react-use-layout-effect@1.1.4(@types/react@19.2.17)(react@19.2.7)': dependencies: react: 19.2.7 optionalDependencies: '@types/react': 19.2.17 - '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)': + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1))(react@19.2.7)': dependencies: '@standard-schema/spec': 1.1.0 '@standard-schema/utils': 0.3.0 @@ -6206,6 +6684,18 @@ snapshots: react: 19.2.7 react-redux: 9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1) + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.18)(react@19.2.7))(react@19.2.7)': + dependencies: + '@standard-schema/spec': 1.1.0 + '@standard-schema/utils': 0.3.0 + immer: 11.1.9 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.2.0 + optionalDependencies: + react: 19.2.7 + react-redux: 9.3.0(@types/react@19.2.18)(react@19.2.7) + '@rolldown/binding-android-arm64@1.1.5': optional: true @@ -6332,12 +6822,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.2 '@tailwindcss/oxide-win32-x64-msvc': 4.3.2 - '@tailwindcss/vite@4.3.2(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': + '@tailwindcss/vite@4.3.2(vite@8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.2 '@tailwindcss/oxide': 4.3.2 tailwindcss: 4.3.2 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) '@tanstack/devtools-event-client@0.4.4': {} @@ -6499,7 +6989,7 @@ snapshots: dependencies: '@types/http-cache-semantics': 4.2.0 '@types/keyv': 3.1.4 - '@types/node': 25.9.4 + '@types/node': 26.1.0 '@types/responselike': 1.0.3 '@types/chai@5.2.3': @@ -6553,7 +7043,7 @@ snapshots: '@types/keyv@3.1.4': dependencies: - '@types/node': 25.9.4 + '@types/node': 26.1.0 '@types/ms@2.1.0': {} @@ -6569,6 +7059,10 @@ snapshots: dependencies: undici-types: 8.3.0 + '@types/node@26.1.2': + dependencies: + undici-types: 8.3.0 + '@types/qrcode@1.5.6': dependencies: '@types/node': 26.1.0 @@ -6577,13 +7071,21 @@ snapshots: dependencies: '@types/react': 19.2.17 + '@types/react-dom@19.2.4(@types/react@19.2.18)': + dependencies: + '@types/react': 19.2.18 + '@types/react@19.2.17': dependencies: csstype: 3.2.3 + '@types/react@19.2.18': + dependencies: + csstype: 3.2.3 + '@types/responselike@1.0.3': dependencies: - '@types/node': 25.9.4 + '@types/node': 26.1.0 '@types/use-sync-external-store@0.0.6': {} @@ -6591,7 +7093,7 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 25.9.4 + '@types/node': 26.1.0 optional: true '@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': @@ -6610,6 +7112,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2))(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2) + '@typescript-eslint/scope-manager': 8.66.0 + '@typescript-eslint/type-utils': 8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2) + '@typescript-eslint/visitor-keys': 8.66.0 + eslint: 10.8.0(jiti@2.7.0)(supports-color@7.2.0) + ignore: 7.0.6 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@7.0.2) + typescript: 7.0.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.62.1 @@ -6622,6 +7140,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2)': + dependencies: + '@typescript-eslint/scope-manager': 8.66.0 + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@7.0.2) + '@typescript-eslint/visitor-keys': 8.66.0 + debug: 4.4.3(supports-color@7.2.0) + eslint: 10.8.0(jiti@2.7.0)(supports-color@7.2.0) + typescript: 7.0.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/project-service@8.62.1(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.62.1(typescript@6.0.3) @@ -6631,15 +7161,33 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.66.0(supports-color@7.2.0)(typescript@7.0.2)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.66.0(typescript@7.0.2) + '@typescript-eslint/types': 8.66.0 + debug: 4.4.3(supports-color@7.2.0) + typescript: 7.0.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.62.1': dependencies: '@typescript-eslint/types': 8.62.1 '@typescript-eslint/visitor-keys': 8.62.1 + '@typescript-eslint/scope-manager@8.66.0': + dependencies: + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/visitor-keys': 8.66.0 + '@typescript-eslint/tsconfig-utils@8.62.1(typescript@6.0.3)': dependencies: typescript: 6.0.3 + '@typescript-eslint/tsconfig-utils@8.66.0(typescript@7.0.2)': + dependencies: + typescript: 7.0.2 + '@typescript-eslint/type-utils@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.62.1 @@ -6652,8 +7200,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/type-utils@8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2)': + dependencies: + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@7.0.2) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2) + debug: 4.4.3(supports-color@7.2.0) + eslint: 10.8.0(jiti@2.7.0)(supports-color@7.2.0) + ts-api-utils: 2.5.0(typescript@7.0.2) + typescript: 7.0.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/types@8.62.1': {} + '@typescript-eslint/types@8.66.0': {} + '@typescript-eslint/typescript-estree@8.62.1(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/project-service': 8.62.1(supports-color@7.2.0)(typescript@6.0.3) @@ -6669,6 +7231,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.66.0(supports-color@7.2.0)(typescript@7.0.2)': + dependencies: + '@typescript-eslint/project-service': 8.66.0(supports-color@7.2.0)(typescript@7.0.2) + '@typescript-eslint/tsconfig-utils': 8.66.0(typescript@7.0.2) + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/visitor-keys': 8.66.0 + debug: 4.4.3(supports-color@7.2.0) + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@7.0.2) + typescript: 7.0.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.62.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0)) @@ -6680,56 +7257,132 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0)) + '@typescript-eslint/scope-manager': 8.66.0 + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@7.0.2) + eslint: 10.8.0(jiti@2.7.0)(supports-color@7.2.0) + typescript: 7.0.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/visitor-keys@8.62.1': dependencies: '@typescript-eslint/types': 8.62.1 eslint-visitor-keys: 5.0.1 - '@vitejs/plugin-react@6.0.3(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': + '@typescript-eslint/visitor-keys@8.66.0': + dependencies: + '@typescript-eslint/types': 8.66.0 + eslint-visitor-keys: 5.0.1 + + '@typescript/typescript-aix-ppc64@7.0.2': + optional: true + + '@typescript/typescript-darwin-arm64@7.0.2': + optional: true + + '@typescript/typescript-darwin-x64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-x64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm@7.0.2': + optional: true + + '@typescript/typescript-linux-loong64@7.0.2': + optional: true + + '@typescript/typescript-linux-mips64el@7.0.2': + optional: true + + '@typescript/typescript-linux-ppc64@7.0.2': + optional: true + + '@typescript/typescript-linux-riscv64@7.0.2': + optional: true + + '@typescript/typescript-linux-s390x@7.0.2': + optional: true + + '@typescript/typescript-linux-x64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-sunos-x64@7.0.2': + optional: true + + '@typescript/typescript-win32-arm64@7.0.2': + optional: true + + '@typescript/typescript-win32-x64@7.0.2': + optional: true + + '@vitejs/plugin-react@6.0.3(vite@8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) - '@vitest/expect@4.1.9': + '@vitest/expect@4.1.10': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.9 - '@vitest/utils': 4.1.9 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 chai: 6.2.2 - tinyrainbow: 3.1.0 + tinyrainbow: 3.1.1 - '@vitest/mocker@4.1.9(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.10(vite@8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.9 + '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) - '@vitest/pretty-format@4.1.9': + '@vitest/pretty-format@4.1.10': dependencies: - tinyrainbow: 3.1.0 + tinyrainbow: 3.1.1 - '@vitest/runner@4.1.9': + '@vitest/runner@4.1.10': dependencies: - '@vitest/utils': 4.1.9 + '@vitest/utils': 4.1.10 pathe: 2.0.3 - '@vitest/snapshot@4.1.9': + '@vitest/snapshot@4.1.10': dependencies: - '@vitest/pretty-format': 4.1.9 - '@vitest/utils': 4.1.9 + '@vitest/pretty-format': 4.1.10 + '@vitest/utils': 4.1.10 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.9': {} + '@vitest/spy@4.1.10': {} - '@vitest/utils@4.1.9': + '@vitest/utils@4.1.10': dependencies: - '@vitest/pretty-format': 4.1.9 + '@vitest/pretty-format': 4.1.10 convert-source-map: 2.0.0 - tinyrainbow: 3.1.0 + tinyrainbow: 3.1.1 '@xmldom/xmldom@0.8.13': {} @@ -6740,11 +7393,11 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 - acorn-jsx@5.3.2(acorn@8.17.0): + acorn-jsx@5.3.2(acorn@8.18.0): dependencies: - acorn: 8.17.0 + acorn: 8.18.0 - acorn@8.17.0: {} + acorn@8.18.0: {} agent-base@7.1.4: {} @@ -6900,6 +7553,10 @@ snapshots: dependencies: balanced-match: 4.0.4 + brace-expansion@5.0.9: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -7045,6 +7702,18 @@ snapshots: - '@types/react' - '@types/react-dom' + cmdk@1.1.1(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.18)(react@19.2.7) + '@radix-ui/react-dialog': 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.18)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + code-block-writer@13.0.3: {} color-convert@2.0.1: @@ -7113,6 +7782,15 @@ snapshots: optionalDependencies: typescript: 6.0.3 + cosmiconfig@9.0.2(typescript@7.0.2): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.3.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 7.0.2 + crelt@1.0.7: {} cross-dirname@0.1.0: @@ -7394,7 +8072,7 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@2.3.0: {} + es-module-lexer@2.3.1: {} es-object-atoms@1.1.2: dependencies: @@ -7447,11 +8125,11 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-react-hooks@7.1.1(eslint@10.6.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): + eslint-plugin-react-hooks@7.1.1(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/parser': 7.29.7 - eslint: 10.6.0(jiti@2.7.0)(supports-color@7.2.0) + eslint: 10.8.0(jiti@2.7.0)(supports-color@7.2.0) hermes-parser: 0.25.1 zod: 4.4.3 zod-validation-error: 4.0.2(zod@4.4.3) @@ -7506,10 +8184,47 @@ snapshots: transitivePeerDependencies: - supports-color + eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0): + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.23.5(supports-color@7.2.0) + '@eslint/config-helpers': 0.7.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.2 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@7.2.0) + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.6 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + espree@11.2.0: dependencies: - acorn: 8.17.0 - acorn-jsx: 5.3.2(acorn@8.17.0) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) eslint-visitor-keys: 5.0.1 esprima@4.0.1: {} @@ -7621,18 +8336,24 @@ snapshots: transitivePeerDependencies: - supports-color - fallow@2.104.0: + fallow-type-aware@3.14.0: + dependencies: + typescript: 7.0.2 + optional: true + + fallow@3.14.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - '@fallow-cli/darwin-arm64': 2.104.0 - '@fallow-cli/darwin-x64': 2.104.0 - '@fallow-cli/linux-arm64-gnu': 2.104.0 - '@fallow-cli/linux-arm64-musl': 2.104.0 - '@fallow-cli/linux-x64-gnu': 2.104.0 - '@fallow-cli/linux-x64-musl': 2.104.0 - '@fallow-cli/win32-arm64-msvc': 2.104.0 - '@fallow-cli/win32-x64-msvc': 2.104.0 + '@fallow-cli/darwin-arm64': 3.14.0 + '@fallow-cli/darwin-x64': 3.14.0 + '@fallow-cli/linux-arm64-gnu': 3.14.0 + '@fallow-cli/linux-arm64-musl': 3.14.0 + '@fallow-cli/linux-x64-gnu': 3.14.0 + '@fallow-cli/linux-x64-musl': 3.14.0 + '@fallow-cli/win32-arm64-msvc': 3.14.0 + '@fallow-cli/win32-x64-msvc': 3.14.0 + fallow-type-aware: 3.14.0 fast-deep-equal@3.1.3: {} @@ -7705,10 +8426,10 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.4.2 + flatted: 3.4.4 keyv: 4.5.4 - flatted@3.4.2: {} + flatted@3.4.4: {} form-data@4.0.6: dependencies: @@ -7851,6 +8572,8 @@ snapshots: globals@17.7.0: {} + globals@17.9.0: {} + globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -7945,6 +8668,8 @@ snapshots: ignore@7.0.5: {} + ignore@7.0.6: {} + immer@10.2.0: {} immer@11.1.9: {} @@ -8315,6 +9040,10 @@ snapshots: dependencies: brace-expansion: 5.0.7 + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.9 + minimatch@3.1.5: dependencies: brace-expansion: 1.1.16 @@ -8423,7 +9152,7 @@ snapshots: object-treeify@1.1.33: {} - obug@2.1.3: {} + obug@2.1.4: {} on-finished@2.4.1: dependencies: @@ -8591,7 +9320,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.9.4: {} + prettier@3.9.6: {} pretty-ms@9.3.0: dependencies: @@ -8685,6 +9414,23 @@ snapshots: '@types/react': 19.2.17 redux: 5.0.1 + react-redux@9.3.0(@types/react@19.2.18)(react@19.2.7): + dependencies: + '@types/use-sync-external-store': 0.0.6 + react: 19.2.7 + use-sync-external-store: 1.6.0(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.18 + + react-redux@9.3.0(@types/react@19.2.18)(react@19.2.7)(redux@5.0.1): + dependencies: + '@types/use-sync-external-store': 0.0.6 + react: 19.2.7 + use-sync-external-store: 1.6.0(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.18 + redux: 5.0.1 + react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.7): dependencies: react: 19.2.7 @@ -8693,6 +9439,14 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + react-remove-scroll-bar@2.3.8(@types/react@19.2.18)(react@19.2.7): + dependencies: + react: 19.2.7 + react-style-singleton: 2.2.3(@types/react@19.2.18)(react@19.2.7) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.18 + react-remove-scroll@2.7.2(@types/react@19.2.17)(react@19.2.7): dependencies: react: 19.2.7 @@ -8704,6 +9458,17 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + react-remove-scroll@2.7.2(@types/react@19.2.18)(react@19.2.7): + dependencies: + react: 19.2.7 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.18)(react@19.2.7) + react-style-singleton: 2.2.3(@types/react@19.2.18)(react@19.2.7) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.18)(react@19.2.7) + use-sidecar: 1.1.3(@types/react@19.2.18)(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.18 + react-resizable-panels@4.12.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: react: 19.2.7 @@ -8717,6 +9482,14 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + react-style-singleton@2.2.3(@types/react@19.2.18)(react@19.2.7): + dependencies: + get-nonce: 1.0.1 + react: 19.2.7 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.18 + react@19.2.7: {} read-binary-file-arch@1.0.6(supports-color@7.2.0): @@ -8745,7 +9518,7 @@ snapshots: recharts@3.10.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7))(react@19.2.7) + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1))(react@19.2.7) clsx: 2.1.1 decimal.js-light: 2.5.1 es-toolkit: 1.49.0 @@ -8765,7 +9538,7 @@ snapshots: recharts@3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7))(react@19.2.7) + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1))(react@19.2.7) clsx: 2.1.1 decimal.js-light: 2.5.1 es-toolkit: 1.49.0 @@ -8783,6 +9556,46 @@ snapshots: - '@types/react' - redux + recharts@3.8.1(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7): + dependencies: + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.18)(react@19.2.7))(react@19.2.7) + clsx: 2.1.1 + decimal.js-light: 2.5.1 + es-toolkit: 1.49.0 + eventemitter3: 5.0.4 + immer: 10.2.0 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-is: 19.2.7 + react-redux: 9.3.0(@types/react@19.2.18)(react@19.2.7) + reselect: 5.1.1 + tiny-invariant: 1.3.3 + use-sync-external-store: 1.6.0(react@19.2.7) + victory-vendor: 37.3.6 + transitivePeerDependencies: + - '@types/react' + - redux + + recharts@3.8.1(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1): + dependencies: + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1))(react@19.2.7) + clsx: 2.1.1 + decimal.js-light: 2.5.1 + es-toolkit: 1.49.0 + eventemitter3: 5.0.4 + immer: 10.2.0 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-is: 19.2.7 + react-redux: 9.3.0(@types/react@19.2.18)(react@19.2.7)(redux@5.0.1) + reselect: 5.1.1 + tiny-invariant: 1.3.3 + use-sync-external-store: 1.6.0(react@19.2.7) + victory-vendor: 37.3.6 + transitivePeerDependencies: + - '@types/react' + - redux + redux-thunk@3.1.0(redux@5.0.1): dependencies: redux: 5.0.1 @@ -8982,6 +9795,46 @@ snapshots: - supports-color - typescript + shadcn@4.12.0(supports-color@7.2.0)(typescript@7.0.2): + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/parser': 7.29.7 + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@dotenvx/dotenvx': 1.75.1 + '@modelcontextprotocol/sdk': 1.29.0(supports-color@7.2.0)(zod@3.25.76) + '@types/validate-npm-package-name': 4.0.2 + browserslist: 4.28.4 + commander: 14.0.3 + cosmiconfig: 9.0.2(typescript@7.0.2) + dedent: 1.7.2 + deepmerge: 4.3.1 + diff: 8.0.4 + execa: 9.6.1 + fast-glob: 3.3.3 + fs-extra: 11.3.6 + fuzzysort: 3.1.0 + kleur: 4.1.5 + open: 11.0.0 + ora: 8.2.0 + postcss: 8.5.16 + postcss-selector-parser: 7.1.4 + prompts: 2.4.2 + recast: 0.23.12 + stringify-object: 5.0.0 + tailwind-merge: 3.6.0 + ts-morph: 26.0.0 + tsconfig-paths: 4.2.0 + undici: 7.28.0 + validate-npm-package-name: 7.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - '@cfworker/json-schema' + - babel-plugin-macros + - supports-color + - typescript + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -9051,7 +9904,7 @@ snapshots: statuses@2.0.2: {} - std-env@4.1.0: {} + std-env@4.2.0: {} stdin-discarder@0.2.2: {} @@ -9141,14 +9994,14 @@ snapshots: tinybench@2.9.0: {} - tinyexec@1.2.4: {} + tinyexec@1.3.0: {} tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.5) picomatch: 4.0.5 - tinyrainbow@3.1.0: {} + tinyrainbow@3.1.1: {} tmp-promise@3.0.3: dependencies: @@ -9170,6 +10023,10 @@ snapshots: dependencies: typescript: 6.0.3 + ts-api-utils@2.5.0(typescript@7.0.2): + dependencies: + typescript: 7.0.2 + ts-morph@26.0.0: dependencies: '@ts-morph/common': 0.27.0 @@ -9213,8 +10070,42 @@ snapshots: transitivePeerDependencies: - supports-color + typescript-eslint@8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2): + dependencies: + '@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2))(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2) + '@typescript-eslint/parser': 8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2) + '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@7.0.2) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@7.0.2) + eslint: 10.8.0(jiti@2.7.0)(supports-color@7.2.0) + typescript: 7.0.2 + transitivePeerDependencies: + - supports-color + typescript@6.0.3: {} + typescript@7.0.2: + optionalDependencies: + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 + undici-types@6.21.0: {} undici-types@7.24.6: {} @@ -9264,6 +10155,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + use-callback-ref@1.3.3(@types/react@19.2.18)(react@19.2.7): + dependencies: + react: 19.2.7 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.18 + use-sidecar@1.1.3(@types/react@19.2.17)(react@19.2.7): dependencies: detect-node-es: 1.1.0 @@ -9272,6 +10170,14 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 + use-sidecar@1.1.3(@types/react@19.2.18)(react@19.2.7): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.7 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.18 + use-sync-external-store@1.6.0(react@19.2.7): dependencies: react: 19.2.7 @@ -9298,6 +10204,15 @@ snapshots: - '@types/react' - '@types/react-dom' + vaul@1.1.2(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + '@radix-ui/react-dialog': 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + victory-vendor@37.3.6: dependencies: '@types/d3-array': 3.2.2 @@ -9315,7 +10230,7 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0): + vite@8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.5 @@ -9323,36 +10238,36 @@ snapshots: rolldown: 1.1.5 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.2 esbuild: 0.28.1 fsevents: 2.3.3 jiti: 2.7.0 yaml: 2.9.0 - vitest@4.1.9(@types/node@26.1.0)(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)): + vitest@4.1.10(@types/node@26.1.2)(vite@8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.9 - '@vitest/mocker': 4.1.9(vite@8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.9 - '@vitest/runner': 4.1.9 - '@vitest/snapshot': 4.1.9 - '@vitest/spy': 4.1.9 - '@vitest/utils': 4.1.9 - es-module-lexer: 2.3.0 + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(vite@8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + es-module-lexer: 2.3.1 expect-type: 1.4.0 magic-string: 0.30.21 - obug: 2.1.3 + obug: 2.1.4 pathe: 2.0.3 picomatch: 4.0.5 - std-env: 4.1.0 + std-env: 4.2.0 tinybench: 2.9.0 - tinyexec: 1.2.4 + tinyexec: 1.3.0 tinyglobby: 0.2.17 - tinyrainbow: 3.1.0 - vite: 8.1.3(@types/node@26.1.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + tinyrainbow: 3.1.1 + vite: 8.1.3(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 26.1.0 + '@types/node': 26.1.2 transitivePeerDependencies: - msw From ec019a4dff358db6bce34d5d4ae054dd0304a155 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 7 Aug 2026 23:05:26 +0200 Subject: [PATCH 58/97] [Upd] User states --- apps/web/src/components/sidebar.test.tsx | 18 ++ apps/web/src/components/sidebar.tsx | 64 ++++---- .../web/src/components/status-options.test.ts | 15 ++ apps/web/src/components/status-options.ts | 13 ++ mtp-type-maps | 2 +- package.json | 4 + packages/cache/src/sync.test.tsx | 19 +++ packages/cache/src/sync.tsx | 57 ++++++- packages/mtp/src/context.test.tsx | 21 +++ packages/mtp/src/context.tsx | 108 ++++++++++-- packages/shared/package.json | 1 + packages/shared/src/data.test.ts | 65 ++++++++ packages/shared/src/data.ts | 146 +++++++++++++---- packages/shared/src/errors.ts | 25 +++ packages/user/src/context.test.tsx | 45 +++++ packages/user/src/context.tsx | 155 ++++++++++++++++-- 16 files changed, 669 insertions(+), 89 deletions(-) create mode 100644 apps/web/src/components/sidebar.test.tsx create mode 100644 apps/web/src/components/status-options.test.ts create mode 100644 apps/web/src/components/status-options.ts create mode 100644 packages/cache/src/sync.test.tsx create mode 100644 packages/mtp/src/context.test.tsx create mode 100644 packages/shared/src/data.test.ts create mode 100644 packages/shared/src/errors.ts create mode 100644 packages/user/src/context.test.tsx diff --git a/apps/web/src/components/sidebar.test.tsx b/apps/web/src/components/sidebar.test.tsx new file mode 100644 index 0000000..7527664 --- /dev/null +++ b/apps/web/src/components/sidebar.test.tsx @@ -0,0 +1,18 @@ +import { describe, expect, it } from "vitest"; + +import { mtp } from "@tensamin/shared/data"; +import { onlineStatusOptions } from "./status-options"; + +describe("sidebar status requests", () => { + it.each(onlineStatusOptions)("sends $label as $value", ({ value }) => { + expect(mtp.SetUserState.request.parse({ UserState: value })).toEqual({ + UserState: value, + }); + }); + + it("keeps status text on the profile operation", () => { + expect(mtp.ChangeUserData.request.parse({ Status: "At lunch" })).toEqual({ + Status: "At lunch", + }); + }); +}); diff --git a/apps/web/src/components/sidebar.tsx b/apps/web/src/components/sidebar.tsx index 10baf34..7a7c58b 100644 --- a/apps/web/src/components/sidebar.tsx +++ b/apps/web/src/components/sidebar.tsx @@ -36,23 +36,19 @@ import { useShowMobileNavbar } from "@/routes/app/useShowMobileNavbar"; import { Ellipsis, Check } from "lucide-react"; import { useState } from "react"; import type { User } from "@tensamin/user/context"; -import type z from "zod"; -import { mtp } from "@tensamin/shared/data"; +import { mtp, userPresencePreferenceSchema } from "@tensamin/shared/data"; import { useMTP } from "@tensamin/mtp"; +import { + onlineStatusLabels, + onlineStatusOptions, + type OnlineStatus, +} from "./status-options"; -type OnlineStatus = z.infer; - -const onlineStatusLabels: Record = { - user_online: "Online", - user_offline: "Offline", - user_dnd: "Do not disturb", - user_idle: "Idle", - user_wc: "Away", - user_borked: "Borked", - iota_offline: "Iota offline", - iota_online: "Iota online", - iota_borked: "Iota borked", -}; +function accountPreference(status: User["OnlineStatus"]): OnlineStatus { + return userPresencePreferenceSchema.safeParse(status).success + ? (status as OnlineStatus) + : "user_online"; +} function StatusDialog({ user, @@ -87,7 +83,7 @@ function StatusDialog({ onOpenChange={(nextOpen) => { if (!nextOpen) { setDraftStatus(user.Status ?? ""); - setDraftOnlineStatus(user.OnlineStatus); + setDraftOnlineStatus(accountPreference(user.OnlineStatus)); setErrorMessage(""); setSaveSucceeded(false); } @@ -126,10 +122,11 @@ function StatusDialog({ - Online - Offline - Idle - Do not disturb + {onlineStatusOptions.map((option) => ( + + {option.label} + + ))} @@ -140,12 +137,9 @@ function StatusDialog({ Cancel} /> + )} + /> + Zoom {zoomLevel + 1}/4 + +
+ + ( + + )} + /> + + {copied ? "Copied!" : "Copy image"} + + + + ( + + + + )} + /> + Open in browser + +
+ +
+ ( + + ( + + )} + /> + Close + + )} + /> +
+ + + setHidden(false)} + style={{ + transform: `translate(-50%, -50%) scale(${zoomLevels[zoomLevel]})`, + }} + className="h-[80vh] rounded-lg object-cover absolute top-1/2 left-1/2 transition-transform duration-200" + /> + + ) : (
diff --git a/packages/chat/src/components/mediaSaveButton.tsx b/packages/chat/src/components/mediaSaveButton.tsx index bfdf6a9..99fbcec 100644 --- a/packages/chat/src/components/mediaSaveButton.tsx +++ b/packages/chat/src/components/mediaSaveButton.tsx @@ -1,6 +1,6 @@ -import { Button, cn } from "@methanium/ui"; +import { Button, cn, useIsMobile } from "@methanium/ui"; import { useStorage } from "@tensamin/storage/context"; -import { Save } from "lucide-react"; +import { Star } from "lucide-react"; import { useEffect, useState } from "react"; export default function MediaSaveButton({ @@ -17,6 +17,7 @@ export default function MediaSaveButton({ url: string; }) { const { load, save } = useStorage(); + const isMobile = useIsMobile(); const [savedMedia, setSavedMedia] = useState(null); const isSaved = savedMedia ? savedMedia.includes(url) : defaultSaved; @@ -40,17 +41,21 @@ export default function MediaSaveButton({ return ( diff --git a/packages/chat/src/components/message.tsx b/packages/chat/src/components/message.tsx index 6dc8dc1..d6b6ea2 100644 --- a/packages/chat/src/components/message.tsx +++ b/packages/chat/src/components/message.tsx @@ -431,7 +431,14 @@ function MessageComponent({ ) : (
{isValidURL ? ( - + ) : ( )} From f83e71be6b218f55386fd742f3997ac4d535651d Mon Sep 17 00:00:00 2001 From: Alois Date: Sun, 9 Aug 2026 20:16:24 +0200 Subject: [PATCH 66/97] fix(legal): license copy script --- licenses/@babel_runtime@7.29.7/LICENSE | 22 - licenses/@base-ui_react@1.6.0/LICENSE | 21 - licenses/@base-ui_utils@0.3.2/LICENSE | 21 - .../LICENSE | 0 .../LICENSE | 0 .../LICENSE | 0 licenses/@floating-ui_core@1.7.5/LICENSE | 20 - licenses/@floating-ui_dom@1.7.6/LICENSE | 20 - licenses/@floating-ui_react-dom@2.1.8/LICENSE | 20 - licenses/@floating-ui_utils@0.2.11/LICENSE | 20 - .../@fontsource-variable_inter@5.2.8/LICENSE | 93 - .../LICENSE | 0 .../LICENSE | 0 licenses/@radix-ui_primitive@1.1.4/LICENSE | 21 - .../LICENSE | 21 - .../@radix-ui_react-context@1.1.4/LICENSE | 21 - .../@radix-ui_react-dialog@1.1.18/LICENSE | 21 - .../LICENSE | 21 - .../LICENSE | 21 - .../LICENSE | 21 - licenses/@radix-ui_react-id@1.1.2/LICENSE | 21 - .../@radix-ui_react-portal@1.1.13/LICENSE | 21 - .../@radix-ui_react-presence@1.1.6/LICENSE | 21 - .../@radix-ui_react-primitive@2.1.7/LICENSE | 21 - licenses/@radix-ui_react-slot@1.3.0/LICENSE | 21 - .../LICENSE | 21 - .../LICENSE | 21 - .../LICENSE | 21 - .../LICENSE | 21 - licenses/@reduxjs_toolkit@2.12.0/LICENSE | 21 - .../LICENSE | 0 .../LICENSE | 21 - .../LICENSE | 0 .../@tanstack_react-router@1.170.17/LICENSE | 21 - .../LICENSE | 0 licenses/@tanstack_react-store@0.11.0/LICENSE | 21 - .../@tanstack_react-virtual@3.14.5/LICENSE | 21 - .../LICENSE | 0 .../@tanstack_router-core@1.171.14/LICENSE | 21 - licenses/@tanstack_store@0.11.0/LICENSE | 21 - .../@tanstack_virtual-core@3.17.3/LICENSE | 21 - .../@tauri-apps_plugin-log@2.8.0/LICENSE.spdx | 20 - .../LICENSE | 0 .../LICENSE | 0 .../LICENSE | 0 .../LICENSE | 0 .../LICENSE | 0 licenses/THIRD_PARTY_NOTICES.md | 949 +---- licenses/aria-hidden@1.2.6/LICENSE | 21 - .../class-variance-authority@0.7.1/LICENSE | 190 - licenses/clsx@2.1.1/license | 9 - licenses/cmdk@1.1.1/LICENSE.md | 21 - licenses/cookie-es@3.1.1/LICENSE | 28 - licenses/d3-array@3.2.4/LICENSE | 13 - licenses/d3-color@3.1.0/LICENSE | 13 - licenses/d3-ease@3.0.1/LICENSE | 28 - licenses/d3-format@3.1.2/LICENSE | 13 - licenses/d3-interpolate@3.0.1/LICENSE | 13 - licenses/d3-path@3.1.0/LICENSE | 13 - licenses/d3-scale@4.0.2/LICENSE | 13 - licenses/d3-shape@3.2.0/LICENSE | 13 - licenses/d3-time-format@4.1.0/LICENSE | 13 - licenses/d3-time@3.1.0/LICENSE | 13 - licenses/d3-timer@3.0.1/LICENSE | 13 - licenses/date-fns@4.4.0/LICENSE.md | 21 - licenses/detect-node-es@1.1.0/LICENSE | 21 - licenses/dijkstrajs@1.0.3/LICENSE.md | 19 - .../LICENSE | 0 licenses/es-toolkit@1.49.0/LICENSE | 21 - .../{eslint@10.6.0 => eslint@10.8.1}/LICENSE | 0 licenses/get-nonce@1.0.1/LICENSE | 21 - .../license | 0 licenses/immer@10.2.0/LICENSE | 21 - licenses/internmap@2.0.3/LICENSE | 13 - licenses/jsonc-parser@3.3.1/LICENSE.md | 21 - .../LICENSE | 0 .../LICENSE | 0 .../LICENSE.md | 0 licenses/next-themes@0.4.6/license.md | 21 - licenses/pngjs@5.0.0/LICENSE | 20 - .../LICENSE | 0 licenses/qrcode@1.5.4/license | 10 - licenses/react-day-picker@10.0.1/LICENSE | 21 - .../LICENSE | 0 .../LICENSE | 0 licenses/react-remove-scroll@2.7.2/LICENSE | 21 - .../react-resizable-panels@4.12.0/LICENSE.md | 21 - licenses/react-style-singleton@2.2.3/LICENSE | 21 - .../{react@19.2.7 => react@19.2.8}/LICENSE | 0 licenses/redux-thunk@3.1.0/LICENSE.md | 21 - licenses/redux@5.0.1/LICENSE.md | 21 - licenses/reselect@5.1.1/LICENSE | 21 - licenses/sbom.cyclonedx.json | 3153 +---------------- licenses/scheduler@0.27.0/LICENSE | 21 - licenses/seroval-plugins@1.5.4/LICENSE | 7 - licenses/seroval@1.5.4/LICENSE | 7 - licenses/shadcn@4.12.0/LICENSE.md | 21 - licenses/tailwind-merge@3.6.0/LICENSE.md | 21 - .../LICENSE | 0 licenses/third-party-credits.json | 1229 +------ licenses/tiny-invariant@1.3.3/LICENSE | 21 - licenses/tslib@2.8.1/LICENSE.txt | 12 - .../LICENSE | 0 licenses/use-callback-ref@1.3.3/LICENSE | 21 - licenses/use-sidecar@1.1.3/LICENSE | 21 - licenses/vaul@1.1.2/LICENSE.md | 9 - .../{vite@8.1.3 => vite@8.2.1}/LICENSE.md | 37 +- .../LICENSE.md | 0 licenses/yaml@2.9.0/LICENSE | 13 - licenses/yargs@15.4.1/LICENSE | 21 - utils/scripts/copy-licenses.ts | 88 +- 111 files changed, 378 insertions(+), 6817 deletions(-) delete mode 100644 licenses/@babel_runtime@7.29.7/LICENSE delete mode 100644 licenses/@base-ui_react@1.6.0/LICENSE delete mode 100644 licenses/@base-ui_utils@0.3.2/LICENSE rename licenses/{@codemirror_lang-markdown@6.5.0 => @codemirror_lang-markdown@6.5.2}/LICENSE (100%) rename licenses/{@codemirror_state@6.7.0 => @codemirror_state@6.7.1}/LICENSE (100%) rename licenses/{@codemirror_view@6.43.4 => @codemirror_view@6.43.8}/LICENSE (100%) delete mode 100644 licenses/@floating-ui_core@1.7.5/LICENSE delete mode 100644 licenses/@floating-ui_dom@1.7.6/LICENSE delete mode 100644 licenses/@floating-ui_react-dom@2.1.8/LICENSE delete mode 100644 licenses/@floating-ui_utils@0.2.11/LICENSE delete mode 100644 licenses/@fontsource-variable_inter@5.2.8/LICENSE rename licenses/{@fontsource-variable_public-sans@5.2.7 => @fontsource-variable_public-sans@5.3.0}/LICENSE (100%) rename licenses/{@livekit_components-react@2.9.21 => @livekit_components-react@2.9.23}/LICENSE (100%) delete mode 100644 licenses/@radix-ui_primitive@1.1.4/LICENSE delete mode 100644 licenses/@radix-ui_react-compose-refs@1.1.3/LICENSE delete mode 100644 licenses/@radix-ui_react-context@1.1.4/LICENSE delete mode 100644 licenses/@radix-ui_react-dialog@1.1.18/LICENSE delete mode 100644 licenses/@radix-ui_react-dismissable-layer@1.1.14/LICENSE delete mode 100644 licenses/@radix-ui_react-focus-guards@1.1.4/LICENSE delete mode 100644 licenses/@radix-ui_react-focus-scope@1.1.11/LICENSE delete mode 100644 licenses/@radix-ui_react-id@1.1.2/LICENSE delete mode 100644 licenses/@radix-ui_react-portal@1.1.13/LICENSE delete mode 100644 licenses/@radix-ui_react-presence@1.1.6/LICENSE delete mode 100644 licenses/@radix-ui_react-primitive@2.1.7/LICENSE delete mode 100644 licenses/@radix-ui_react-slot@1.3.0/LICENSE delete mode 100644 licenses/@radix-ui_react-use-callback-ref@1.1.2/LICENSE delete mode 100644 licenses/@radix-ui_react-use-controllable-state@1.2.3/LICENSE delete mode 100644 licenses/@radix-ui_react-use-effect-event@0.0.5/LICENSE delete mode 100644 licenses/@radix-ui_react-use-layout-effect@1.1.2/LICENSE delete mode 100644 licenses/@reduxjs_toolkit@2.12.0/LICENSE rename licenses/{@tailwindcss_vite@4.3.2 => @tailwindcss_vite@4.3.3}/LICENSE (100%) delete mode 100644 licenses/@tanstack_devtools-event-client@0.5.0/LICENSE rename licenses/{@tanstack_history@1.162.0 => @tanstack_react-query@5.101.4}/LICENSE (100%) delete mode 100644 licenses/@tanstack_react-router@1.170.17/LICENSE rename licenses/{@tanstack_query-core@5.101.2 => @tanstack_react-router@1.170.23}/LICENSE (100%) delete mode 100644 licenses/@tanstack_react-store@0.11.0/LICENSE delete mode 100644 licenses/@tanstack_react-virtual@3.14.5/LICENSE rename licenses/{@tanstack_react-query@5.101.2 => @tanstack_react-virtual@3.14.9}/LICENSE (100%) delete mode 100644 licenses/@tanstack_router-core@1.171.14/LICENSE delete mode 100644 licenses/@tanstack_store@0.11.0/LICENSE delete mode 100644 licenses/@tanstack_virtual-core@3.17.3/LICENSE delete mode 100644 licenses/@tauri-apps_plugin-log@2.8.0/LICENSE.spdx rename licenses/{@types_node@25.9.4 => @types_node@26.2.0}/LICENSE (100%) rename licenses/{@types_react-dom@19.2.3 => @types_react-dom@19.2.4}/LICENSE (100%) rename licenses/{@types_react@19.2.17 => @types_react@19.2.18}/LICENSE (100%) rename licenses/{@typescript-eslint_parser@8.62.1 => @typescript-eslint_parser@8.66.0}/LICENSE (100%) rename licenses/{@vitejs_plugin-react@6.0.3 => @vitejs_plugin-react@6.0.5}/LICENSE (100%) delete mode 100644 licenses/aria-hidden@1.2.6/LICENSE delete mode 100644 licenses/class-variance-authority@0.7.1/LICENSE delete mode 100644 licenses/clsx@2.1.1/license delete mode 100644 licenses/cmdk@1.1.1/LICENSE.md delete mode 100644 licenses/cookie-es@3.1.1/LICENSE delete mode 100644 licenses/d3-array@3.2.4/LICENSE delete mode 100644 licenses/d3-color@3.1.0/LICENSE delete mode 100644 licenses/d3-ease@3.0.1/LICENSE delete mode 100644 licenses/d3-format@3.1.2/LICENSE delete mode 100644 licenses/d3-interpolate@3.0.1/LICENSE delete mode 100644 licenses/d3-path@3.1.0/LICENSE delete mode 100644 licenses/d3-scale@4.0.2/LICENSE delete mode 100644 licenses/d3-shape@3.2.0/LICENSE delete mode 100644 licenses/d3-time-format@4.1.0/LICENSE delete mode 100644 licenses/d3-time@3.1.0/LICENSE delete mode 100644 licenses/d3-timer@3.0.1/LICENSE delete mode 100644 licenses/date-fns@4.4.0/LICENSE.md delete mode 100644 licenses/detect-node-es@1.1.0/LICENSE delete mode 100644 licenses/dijkstrajs@1.0.3/LICENSE.md rename licenses/{electron@39.8.10 => electron@43.3.0}/LICENSE (100%) delete mode 100644 licenses/es-toolkit@1.49.0/LICENSE rename licenses/{eslint@10.6.0 => eslint@10.8.1}/LICENSE (100%) delete mode 100644 licenses/get-nonce@1.0.1/LICENSE rename licenses/{globals@17.7.0 => globals@17.9.0}/license (100%) delete mode 100644 licenses/immer@10.2.0/LICENSE delete mode 100644 licenses/internmap@2.0.3/LICENSE delete mode 100644 licenses/jsonc-parser@3.3.1/LICENSE.md rename licenses/{livekit-client@2.20.0 => livekit-client@2.21.0}/LICENSE (100%) rename licenses/{lucide-react@1.23.0 => lucide-react@1.30.0}/LICENSE (100%) rename licenses/{motion@12.42.2 => motion@13.0.0}/LICENSE.md (100%) delete mode 100644 licenses/next-themes@0.4.6/license.md delete mode 100644 licenses/pngjs@5.0.0/LICENSE rename licenses/{prettier@3.9.4 => prettier@3.9.6}/LICENSE (100%) delete mode 100644 licenses/qrcode@1.5.4/license delete mode 100644 licenses/react-day-picker@10.0.1/LICENSE rename licenses/{react-dom@19.2.7 => react-dom@19.2.8}/LICENSE (100%) rename licenses/{react-is@19.2.7 => react-is@19.2.8}/LICENSE (100%) delete mode 100644 licenses/react-remove-scroll@2.7.2/LICENSE delete mode 100644 licenses/react-resizable-panels@4.12.0/LICENSE.md delete mode 100644 licenses/react-style-singleton@2.2.3/LICENSE rename licenses/{react@19.2.7 => react@19.2.8}/LICENSE (100%) delete mode 100644 licenses/redux-thunk@3.1.0/LICENSE.md delete mode 100644 licenses/redux@5.0.1/LICENSE.md delete mode 100644 licenses/reselect@5.1.1/LICENSE delete mode 100644 licenses/scheduler@0.27.0/LICENSE delete mode 100644 licenses/seroval-plugins@1.5.4/LICENSE delete mode 100644 licenses/seroval@1.5.4/LICENSE delete mode 100644 licenses/shadcn@4.12.0/LICENSE.md delete mode 100644 licenses/tailwind-merge@3.6.0/LICENSE.md rename licenses/{tailwindcss@4.3.2 => tailwindcss@4.3.3}/LICENSE (100%) delete mode 100644 licenses/tiny-invariant@1.3.3/LICENSE delete mode 100644 licenses/tslib@2.8.1/LICENSE.txt rename licenses/{typescript-eslint@8.62.1 => typescript-eslint@8.66.0}/LICENSE (100%) delete mode 100644 licenses/use-callback-ref@1.3.3/LICENSE delete mode 100644 licenses/use-sidecar@1.1.3/LICENSE delete mode 100644 licenses/vaul@1.1.2/LICENSE.md rename licenses/{vite@8.1.3 => vite@8.2.1}/LICENSE.md (98%) rename licenses/{vitest@4.1.9 => vitest@4.1.10}/LICENSE.md (100%) delete mode 100644 licenses/yaml@2.9.0/LICENSE delete mode 100644 licenses/yargs@15.4.1/LICENSE diff --git a/licenses/@babel_runtime@7.29.7/LICENSE b/licenses/@babel_runtime@7.29.7/LICENSE deleted file mode 100644 index f31575e..0000000 --- a/licenses/@babel_runtime@7.29.7/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2014-present Sebastian McKenzie and other contributors - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/@base-ui_react@1.6.0/LICENSE b/licenses/@base-ui_react@1.6.0/LICENSE deleted file mode 100644 index 510c55e..0000000 --- a/licenses/@base-ui_react@1.6.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 Material-UI SAS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@base-ui_utils@0.3.2/LICENSE b/licenses/@base-ui_utils@0.3.2/LICENSE deleted file mode 100644 index 510c55e..0000000 --- a/licenses/@base-ui_utils@0.3.2/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 Material-UI SAS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@codemirror_lang-markdown@6.5.0/LICENSE b/licenses/@codemirror_lang-markdown@6.5.2/LICENSE similarity index 100% rename from licenses/@codemirror_lang-markdown@6.5.0/LICENSE rename to licenses/@codemirror_lang-markdown@6.5.2/LICENSE diff --git a/licenses/@codemirror_state@6.7.0/LICENSE b/licenses/@codemirror_state@6.7.1/LICENSE similarity index 100% rename from licenses/@codemirror_state@6.7.0/LICENSE rename to licenses/@codemirror_state@6.7.1/LICENSE diff --git a/licenses/@codemirror_view@6.43.4/LICENSE b/licenses/@codemirror_view@6.43.8/LICENSE similarity index 100% rename from licenses/@codemirror_view@6.43.4/LICENSE rename to licenses/@codemirror_view@6.43.8/LICENSE diff --git a/licenses/@floating-ui_core@1.7.5/LICENSE b/licenses/@floating-ui_core@1.7.5/LICENSE deleted file mode 100644 index 639cdc6..0000000 --- a/licenses/@floating-ui_core@1.7.5/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -MIT License - -Copyright (c) 2021-present Floating UI contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/@floating-ui_dom@1.7.6/LICENSE b/licenses/@floating-ui_dom@1.7.6/LICENSE deleted file mode 100644 index 639cdc6..0000000 --- a/licenses/@floating-ui_dom@1.7.6/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -MIT License - -Copyright (c) 2021-present Floating UI contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/@floating-ui_react-dom@2.1.8/LICENSE b/licenses/@floating-ui_react-dom@2.1.8/LICENSE deleted file mode 100644 index 639cdc6..0000000 --- a/licenses/@floating-ui_react-dom@2.1.8/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -MIT License - -Copyright (c) 2021-present Floating UI contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/@floating-ui_utils@0.2.11/LICENSE b/licenses/@floating-ui_utils@0.2.11/LICENSE deleted file mode 100644 index 639cdc6..0000000 --- a/licenses/@floating-ui_utils@0.2.11/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -MIT License - -Copyright (c) 2021-present Floating UI contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/@fontsource-variable_inter@5.2.8/LICENSE b/licenses/@fontsource-variable_inter@5.2.8/LICENSE deleted file mode 100644 index 40589da..0000000 --- a/licenses/@fontsource-variable_inter@5.2.8/LICENSE +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2016 The Inter Project Authors (https://github.com/rsms/inter) Inter-Italic[opsz,wght].ttf: Copyright 2016 The Inter Project Authors (https://github.com/rsms/inter) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/licenses/@fontsource-variable_public-sans@5.2.7/LICENSE b/licenses/@fontsource-variable_public-sans@5.3.0/LICENSE similarity index 100% rename from licenses/@fontsource-variable_public-sans@5.2.7/LICENSE rename to licenses/@fontsource-variable_public-sans@5.3.0/LICENSE diff --git a/licenses/@livekit_components-react@2.9.21/LICENSE b/licenses/@livekit_components-react@2.9.23/LICENSE similarity index 100% rename from licenses/@livekit_components-react@2.9.21/LICENSE rename to licenses/@livekit_components-react@2.9.23/LICENSE diff --git a/licenses/@radix-ui_primitive@1.1.4/LICENSE b/licenses/@radix-ui_primitive@1.1.4/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_primitive@1.1.4/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-compose-refs@1.1.3/LICENSE b/licenses/@radix-ui_react-compose-refs@1.1.3/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-compose-refs@1.1.3/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-context@1.1.4/LICENSE b/licenses/@radix-ui_react-context@1.1.4/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-context@1.1.4/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-dialog@1.1.18/LICENSE b/licenses/@radix-ui_react-dialog@1.1.18/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-dialog@1.1.18/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-dismissable-layer@1.1.14/LICENSE b/licenses/@radix-ui_react-dismissable-layer@1.1.14/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-dismissable-layer@1.1.14/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-focus-guards@1.1.4/LICENSE b/licenses/@radix-ui_react-focus-guards@1.1.4/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-focus-guards@1.1.4/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-focus-scope@1.1.11/LICENSE b/licenses/@radix-ui_react-focus-scope@1.1.11/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-focus-scope@1.1.11/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-id@1.1.2/LICENSE b/licenses/@radix-ui_react-id@1.1.2/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-id@1.1.2/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-portal@1.1.13/LICENSE b/licenses/@radix-ui_react-portal@1.1.13/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-portal@1.1.13/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-presence@1.1.6/LICENSE b/licenses/@radix-ui_react-presence@1.1.6/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-presence@1.1.6/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-primitive@2.1.7/LICENSE b/licenses/@radix-ui_react-primitive@2.1.7/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-primitive@2.1.7/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-slot@1.3.0/LICENSE b/licenses/@radix-ui_react-slot@1.3.0/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-slot@1.3.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-use-callback-ref@1.1.2/LICENSE b/licenses/@radix-ui_react-use-callback-ref@1.1.2/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-use-callback-ref@1.1.2/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-use-controllable-state@1.2.3/LICENSE b/licenses/@radix-ui_react-use-controllable-state@1.2.3/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-use-controllable-state@1.2.3/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-use-effect-event@0.0.5/LICENSE b/licenses/@radix-ui_react-use-effect-event@0.0.5/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-use-effect-event@0.0.5/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@radix-ui_react-use-layout-effect@1.1.2/LICENSE b/licenses/@radix-ui_react-use-layout-effect@1.1.2/LICENSE deleted file mode 100644 index a18858f..0000000 --- a/licenses/@radix-ui_react-use-layout-effect@1.1.2/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 WorkOS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@reduxjs_toolkit@2.12.0/LICENSE b/licenses/@reduxjs_toolkit@2.12.0/LICENSE deleted file mode 100644 index 1daa252..0000000 --- a/licenses/@reduxjs_toolkit@2.12.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 Mark Erikson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@tailwindcss_vite@4.3.2/LICENSE b/licenses/@tailwindcss_vite@4.3.3/LICENSE similarity index 100% rename from licenses/@tailwindcss_vite@4.3.2/LICENSE rename to licenses/@tailwindcss_vite@4.3.3/LICENSE diff --git a/licenses/@tanstack_devtools-event-client@0.5.0/LICENSE b/licenses/@tanstack_devtools-event-client@0.5.0/LICENSE deleted file mode 100644 index 0ede5e8..0000000 --- a/licenses/@tanstack_devtools-event-client@0.5.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 TanStack - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@tanstack_history@1.162.0/LICENSE b/licenses/@tanstack_react-query@5.101.4/LICENSE similarity index 100% rename from licenses/@tanstack_history@1.162.0/LICENSE rename to licenses/@tanstack_react-query@5.101.4/LICENSE diff --git a/licenses/@tanstack_react-router@1.170.17/LICENSE b/licenses/@tanstack_react-router@1.170.17/LICENSE deleted file mode 100644 index 1869e21..0000000 --- a/licenses/@tanstack_react-router@1.170.17/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021-present Tanner Linsley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@tanstack_query-core@5.101.2/LICENSE b/licenses/@tanstack_react-router@1.170.23/LICENSE similarity index 100% rename from licenses/@tanstack_query-core@5.101.2/LICENSE rename to licenses/@tanstack_react-router@1.170.23/LICENSE diff --git a/licenses/@tanstack_react-store@0.11.0/LICENSE b/licenses/@tanstack_react-store@0.11.0/LICENSE deleted file mode 100644 index 77eca38..0000000 --- a/licenses/@tanstack_react-store@0.11.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Tanner Linsley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@tanstack_react-virtual@3.14.5/LICENSE b/licenses/@tanstack_react-virtual@3.14.5/LICENSE deleted file mode 100644 index 1869e21..0000000 --- a/licenses/@tanstack_react-virtual@3.14.5/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021-present Tanner Linsley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@tanstack_react-query@5.101.2/LICENSE b/licenses/@tanstack_react-virtual@3.14.9/LICENSE similarity index 100% rename from licenses/@tanstack_react-query@5.101.2/LICENSE rename to licenses/@tanstack_react-virtual@3.14.9/LICENSE diff --git a/licenses/@tanstack_router-core@1.171.14/LICENSE b/licenses/@tanstack_router-core@1.171.14/LICENSE deleted file mode 100644 index 1869e21..0000000 --- a/licenses/@tanstack_router-core@1.171.14/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021-present Tanner Linsley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@tanstack_store@0.11.0/LICENSE b/licenses/@tanstack_store@0.11.0/LICENSE deleted file mode 100644 index 77eca38..0000000 --- a/licenses/@tanstack_store@0.11.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Tanner Linsley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@tanstack_virtual-core@3.17.3/LICENSE b/licenses/@tanstack_virtual-core@3.17.3/LICENSE deleted file mode 100644 index 1869e21..0000000 --- a/licenses/@tanstack_virtual-core@3.17.3/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021-present Tanner Linsley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/@tauri-apps_plugin-log@2.8.0/LICENSE.spdx b/licenses/@tauri-apps_plugin-log@2.8.0/LICENSE.spdx deleted file mode 100644 index cdd0df5..0000000 --- a/licenses/@tauri-apps_plugin-log@2.8.0/LICENSE.spdx +++ /dev/null @@ -1,20 +0,0 @@ -SPDXVersion: SPDX-2.1 -DataLicense: CC0-1.0 -PackageName: tauri -DataFormat: SPDXRef-1 -PackageSupplier: Organization: The Tauri Programme in the Commons Conservancy -PackageHomePage: https://tauri.app -PackageLicenseDeclared: Apache-2.0 -PackageLicenseDeclared: MIT -PackageCopyrightText: 2019-2022, The Tauri Programme in the Commons Conservancy -PackageSummary: Tauri is a rust project that enables developers to make secure -and small desktop applications using a web frontend. - -PackageComment: The package includes the following libraries; see -Relationship information. - -Created: 2019-05-20T09:00:00Z -PackageDownloadLocation: git://github.com/tauri-apps/tauri -PackageDownloadLocation: git+https://github.com/tauri-apps/tauri.git -PackageDownloadLocation: git+ssh://github.com/tauri-apps/tauri.git -Creator: Person: Daniel Thompson-Yvetot \ No newline at end of file diff --git a/licenses/@types_node@25.9.4/LICENSE b/licenses/@types_node@26.2.0/LICENSE similarity index 100% rename from licenses/@types_node@25.9.4/LICENSE rename to licenses/@types_node@26.2.0/LICENSE diff --git a/licenses/@types_react-dom@19.2.3/LICENSE b/licenses/@types_react-dom@19.2.4/LICENSE similarity index 100% rename from licenses/@types_react-dom@19.2.3/LICENSE rename to licenses/@types_react-dom@19.2.4/LICENSE diff --git a/licenses/@types_react@19.2.17/LICENSE b/licenses/@types_react@19.2.18/LICENSE similarity index 100% rename from licenses/@types_react@19.2.17/LICENSE rename to licenses/@types_react@19.2.18/LICENSE diff --git a/licenses/@typescript-eslint_parser@8.62.1/LICENSE b/licenses/@typescript-eslint_parser@8.66.0/LICENSE similarity index 100% rename from licenses/@typescript-eslint_parser@8.62.1/LICENSE rename to licenses/@typescript-eslint_parser@8.66.0/LICENSE diff --git a/licenses/@vitejs_plugin-react@6.0.3/LICENSE b/licenses/@vitejs_plugin-react@6.0.5/LICENSE similarity index 100% rename from licenses/@vitejs_plugin-react@6.0.3/LICENSE rename to licenses/@vitejs_plugin-react@6.0.5/LICENSE diff --git a/licenses/THIRD_PARTY_NOTICES.md b/licenses/THIRD_PARTY_NOTICES.md index 138d98a..bda5f0c 100644 --- a/licenses/THIRD_PARTY_NOTICES.md +++ b/licenses/THIRD_PARTY_NOTICES.md @@ -2,35 +2,6 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules folders. -## @babel/runtime@7.29.7 - -- License: MIT -- Homepage: https://babel.dev/docs/en/next/babel-runtime -- Repository: https://github.com/babel/babel.git -- Description: babel's modular runtime helpers -- Included files: LICENSE -- Folder: `licenses/@babel_runtime@7.29.7` -- Source package dir: `apps/web/node_modules/@babel/runtime` - -## @base-ui/react@1.6.0 - -- License: MIT -- Homepage: https://base-ui.com -- Repository: git+https://github.com/mui/base-ui.git -- Description: Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features. -- Included files: LICENSE -- Folder: `licenses/@base-ui_react@1.6.0` -- Source package dir: `apps/web/node_modules/@base-ui/react` - -## @base-ui/utils@0.3.2 - -- License: MIT -- Repository: git+https://github.com/mui/base-ui.git -- Description: A collection of React utility functions for Base UI. -- Included files: LICENSE -- Folder: `licenses/@base-ui_utils@0.3.2` -- Source package dir: `apps/web/node_modules/@base-ui/utils` - ## @codemirror/autocomplete@6.20.3 - License: MIT @@ -49,13 +20,13 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@codemirror_commands@6.10.4` - Source package dir: `packages/markdown/node_modules/@codemirror/commands` -## @codemirror/lang-markdown@6.5.0 +## @codemirror/lang-markdown@6.5.2 - License: MIT -- Repository: https://github.com/codemirror/lang-markdown.git +- Repository: git+https://code.haverbeke.berlin/codemirror/lang-markdown.git - Description: Markdown language support for the CodeMirror code editor - Included files: LICENSE -- Folder: `licenses/@codemirror_lang-markdown@6.5.0` +- Folder: `licenses/@codemirror_lang-markdown@6.5.2` - Source package dir: `packages/markdown/node_modules/@codemirror/lang-markdown` ## @codemirror/language@6.12.4 @@ -67,22 +38,22 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@codemirror_language@6.12.4` - Source package dir: `packages/markdown/node_modules/@codemirror/language` -## @codemirror/state@6.7.0 +## @codemirror/state@6.7.1 - License: MIT - Repository: git+https://code.haverbeke.berlin/codemirror/state.git - Description: Editor state data structures for the CodeMirror code editor - Included files: LICENSE -- Folder: `licenses/@codemirror_state@6.7.0` +- Folder: `licenses/@codemirror_state@6.7.1` - Source package dir: `packages/markdown/node_modules/@codemirror/state` -## @codemirror/view@6.43.4 +## @codemirror/view@6.43.8 - License: MIT - Repository: git+https://code.haverbeke.berlin/codemirror/view.git - Description: DOM view component for the CodeMirror code editor - Included files: LICENSE -- Folder: `licenses/@codemirror_view@6.43.4` +- Folder: `licenses/@codemirror_view@6.43.8` - Source package dir: `packages/markdown/node_modules/@codemirror/view` ## @eslint/js@10.0.1 @@ -95,72 +66,22 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@eslint_js@10.0.1` - Source package dir: `apps/web/node_modules/@eslint/js` -## @floating-ui/core@1.7.5 - -- License: MIT -- Homepage: https://floating-ui.com -- Repository: https://github.com/floating-ui/floating-ui.git -- Description: Positioning library for floating elements: tooltips, popovers, dropdowns, and more -- Included files: LICENSE -- Folder: `licenses/@floating-ui_core@1.7.5` -- Source package dir: `apps/web/node_modules/@floating-ui/core` - -## @floating-ui/dom@1.7.6 - -- License: MIT -- Homepage: https://floating-ui.com -- Repository: https://github.com/floating-ui/floating-ui.git -- Description: Floating UI for the web -- Included files: LICENSE -- Folder: `licenses/@floating-ui_dom@1.7.6` -- Source package dir: `apps/web/node_modules/@floating-ui/dom` - -## @floating-ui/react-dom@2.1.8 - -- License: MIT -- Homepage: https://floating-ui.com/docs/react-dom -- Repository: https://github.com/floating-ui/floating-ui.git -- Description: Floating UI for React DOM -- Included files: LICENSE -- Folder: `licenses/@floating-ui_react-dom@2.1.8` -- Source package dir: `apps/web/node_modules/@floating-ui/react-dom` - -## @floating-ui/utils@0.2.11 - -- License: MIT -- Homepage: https://floating-ui.com -- Repository: https://github.com/floating-ui/floating-ui.git -- Description: Utilities for Floating UI -- Included files: LICENSE -- Folder: `licenses/@floating-ui_utils@0.2.11` -- Source package dir: `apps/web/node_modules/@floating-ui/utils` - -## @fontsource-variable/inter@5.2.8 - -- License: OFL-1.1 -- Homepage: https://fontsource.org/fonts/inter -- Repository: git+https://github.com/fontsource/font-files.git -- Description: Self-host the Inter font in a neatly bundled NPM package. -- Included files: LICENSE -- Folder: `licenses/@fontsource-variable_inter@5.2.8` -- Source package dir: `apps/web/node_modules/@fontsource-variable/inter` - -## @fontsource-variable/public-sans@5.2.7 +## @fontsource-variable/public-sans@5.3.0 - License: OFL-1.1 - Homepage: https://fontsource.org/fonts/public-sans - Repository: git+https://github.com/fontsource/font-files.git - Description: Self-host the Public Sans font in a neatly bundled NPM package. - Included files: LICENSE -- Folder: `licenses/@fontsource-variable_public-sans@5.2.7` +- Folder: `licenses/@fontsource-variable_public-sans@5.3.0` - Source package dir: `apps/web/node_modules/@fontsource-variable/public-sans` -## @livekit/components-react@2.9.21 +## @livekit/components-react@2.9.23 - License: Apache-2.0 - Repository: https://github.com/livekit/components-js.git - Included files: LICENSE -- Folder: `licenses/@livekit_components-react@2.9.21` +- Folder: `licenses/@livekit_components-react@2.9.23` - Source package dir: `packages/call/node_modules/@livekit/components-react` ## @methanium/ui@0.0.22 @@ -170,190 +91,16 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@methanium_ui@0.0.22` - Source package dir: `apps/tauri/node_modules/@methanium/ui` -## @radix-ui/primitive@1.1.4 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_primitive@1.1.4` -- Source package dir: `apps/web/node_modules/@radix-ui/primitive` - -## @radix-ui/react-compose-refs@1.1.3 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-compose-refs@1.1.3` -- Source package dir: `apps/web/node_modules/@radix-ui/react-compose-refs` - -## @radix-ui/react-context@1.1.4 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-context@1.1.4` -- Source package dir: `apps/web/node_modules/@radix-ui/react-context` - -## @radix-ui/react-dialog@1.1.18 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-dialog@1.1.18` -- Source package dir: `apps/web/node_modules/@radix-ui/react-dialog` - -## @radix-ui/react-dismissable-layer@1.1.14 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-dismissable-layer@1.1.14` -- Source package dir: `apps/web/node_modules/@radix-ui/react-dismissable-layer` - -## @radix-ui/react-focus-guards@1.1.4 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-focus-guards@1.1.4` -- Source package dir: `apps/web/node_modules/@radix-ui/react-focus-guards` - -## @radix-ui/react-focus-scope@1.1.11 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-focus-scope@1.1.11` -- Source package dir: `apps/web/node_modules/@radix-ui/react-focus-scope` - -## @radix-ui/react-id@1.1.2 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-id@1.1.2` -- Source package dir: `apps/web/node_modules/@radix-ui/react-id` - -## @radix-ui/react-portal@1.1.13 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-portal@1.1.13` -- Source package dir: `apps/web/node_modules/@radix-ui/react-portal` - -## @radix-ui/react-presence@1.1.6 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-presence@1.1.6` -- Source package dir: `apps/web/node_modules/@radix-ui/react-presence` - -## @radix-ui/react-primitive@2.1.7 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-primitive@2.1.7` -- Source package dir: `apps/web/node_modules/@radix-ui/react-primitive` - -## @radix-ui/react-slot@1.3.0 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-slot@1.3.0` -- Source package dir: `apps/web/node_modules/@radix-ui/react-slot` - -## @radix-ui/react-use-callback-ref@1.1.2 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-use-callback-ref@1.1.2` -- Source package dir: `apps/web/node_modules/@radix-ui/react-use-callback-ref` - -## @radix-ui/react-use-controllable-state@1.2.3 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-use-controllable-state@1.2.3` -- Source package dir: `apps/web/node_modules/@radix-ui/react-use-controllable-state` - -## @radix-ui/react-use-effect-event@0.0.5 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-use-effect-event@0.0.5` -- Source package dir: `apps/web/node_modules/@radix-ui/react-use-effect-event` - -## @radix-ui/react-use-layout-effect@1.1.2 - -- License: MIT -- Homepage: https://radix-ui.com/primitives -- Repository: git+https://github.com/radix-ui/primitives.git -- Included files: LICENSE -- Folder: `licenses/@radix-ui_react-use-layout-effect@1.1.2` -- Source package dir: `apps/web/node_modules/@radix-ui/react-use-layout-effect` - -## @reduxjs/toolkit@2.12.0 - -- License: MIT -- Homepage: https://redux-toolkit.js.org -- Repository: git+https://github.com/reduxjs/redux-toolkit.git -- Description: The official, opinionated, batteries-included toolset for efficient Redux development -- Included files: LICENSE -- Folder: `licenses/@reduxjs_toolkit@2.12.0` -- Source package dir: `apps/web/node_modules/@reduxjs/toolkit` - -## @tailwindcss/vite@4.3.2 +## @tailwindcss/vite@4.3.3 - License: MIT - Homepage: https://tailwindcss.com - Repository: https://github.com/tailwindlabs/tailwindcss.git - Description: A utility-first CSS framework for rapidly building custom user interfaces. - Included files: LICENSE -- Folder: `licenses/@tailwindcss_vite@4.3.2` +- Folder: `licenses/@tailwindcss_vite@4.3.3` - Source package dir: `apps/web/node_modules/@tailwindcss/vite` -## @tanstack/devtools-event-client@0.5.0 - -- License: MIT -- Homepage: https://tanstack.com/devtools -- Repository: git+https://github.com/TanStack/devtools.git -- Description: TanStack Event Client is a lightweight event client for TanStack Devtools event bus. -- Included files: LICENSE -- Folder: `licenses/@tanstack_devtools-event-client@0.5.0` -- Source package dir: `apps/web/node_modules/@tanstack/devtools-event-client` - -## @tanstack/history@1.162.0 - -- License: MIT -- Homepage: https://tanstack.com/router -- Repository: git+https://github.com/TanStack/router.git -- Description: Modern and scalable routing for React applications -- Included files: LICENSE -- Folder: `licenses/@tanstack_history@1.162.0` -- Source package dir: `apps/web/node_modules/@tanstack/history` - ## @tanstack/pacer@0.21.1 - License: MIT @@ -364,16 +111,6 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@tanstack_pacer@0.21.1` - Source package dir: `packages/chat/node_modules/@tanstack/pacer` -## @tanstack/query-core@5.101.2 - -- License: MIT -- Homepage: https://tanstack.com/query -- Repository: git+https://github.com/TanStack/query.git -- Description: The framework agnostic core that powers TanStack Query -- Included files: LICENSE -- Folder: `licenses/@tanstack_query-core@5.101.2` -- Source package dir: `apps/web/node_modules/@tanstack/query-core` - ## @tanstack/react-hotkeys@0.10.0 - License: MIT @@ -384,76 +121,36 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@tanstack_react-hotkeys@0.10.0` - Source package dir: `packages/hotkeys/node_modules/@tanstack/react-hotkeys` -## @tanstack/react-query@5.101.2 +## @tanstack/react-query@5.101.4 - License: MIT - Homepage: https://tanstack.com/query - Repository: git+https://github.com/TanStack/query.git - Description: Hooks for managing, caching and syncing asynchronous and remote data in React - Included files: LICENSE -- Folder: `licenses/@tanstack_react-query@5.101.2` +- Folder: `licenses/@tanstack_react-query@5.101.4` - Source package dir: `packages/chat/node_modules/@tanstack/react-query` -## @tanstack/react-router@1.170.17 +## @tanstack/react-router@1.170.23 - License: MIT - Homepage: https://tanstack.com/router - Repository: git+https://github.com/TanStack/router.git - Description: Modern and scalable routing for React applications - Included files: LICENSE -- Folder: `licenses/@tanstack_react-router@1.170.17` +- Folder: `licenses/@tanstack_react-router@1.170.23` - Source package dir: `apps/web/node_modules/@tanstack/react-router` -## @tanstack/react-store@0.11.0 - -- License: MIT -- Homepage: https://tanstack.com/store -- Repository: https://github.com/TanStack/store.git -- Description: Framework agnostic type-safe store w/ reactive framework adapters -- Included files: LICENSE -- Folder: `licenses/@tanstack_react-store@0.11.0` -- Source package dir: `apps/web/node_modules/@tanstack/react-store` - -## @tanstack/react-virtual@3.14.5 +## @tanstack/react-virtual@3.14.9 - License: MIT - Homepage: https://tanstack.com/virtual - Repository: git+https://github.com/TanStack/virtual.git - Description: Headless UI for virtualizing scrollable elements in React - Included files: LICENSE -- Folder: `licenses/@tanstack_react-virtual@3.14.5` +- Folder: `licenses/@tanstack_react-virtual@3.14.9` - Source package dir: `apps/web/node_modules/@tanstack/react-virtual` -## @tanstack/router-core@1.171.14 - -- License: MIT -- Homepage: https://tanstack.com/router -- Repository: git+https://github.com/TanStack/router.git -- Description: Modern and scalable routing for React applications -- Included files: LICENSE -- Folder: `licenses/@tanstack_router-core@1.171.14` -- Source package dir: `apps/web/node_modules/@tanstack/router-core` - -## @tanstack/store@0.11.0 - -- License: MIT -- Homepage: https://tanstack.com/store -- Repository: git+https://github.com/TanStack/store.git -- Description: Framework agnostic type-safe store w/ reactive framework adapters -- Included files: LICENSE -- Folder: `licenses/@tanstack_store@0.11.0` -- Source package dir: `apps/web/node_modules/@tanstack/store` - -## @tanstack/virtual-core@3.17.3 - -- License: MIT -- Homepage: https://tanstack.com/virtual -- Repository: git+https://github.com/TanStack/virtual.git -- Description: Headless UI for virtualizing scrollable elements in TS/JS + Frameworks -- Included files: LICENSE -- Folder: `licenses/@tanstack_virtual-core@3.17.3` -- Source package dir: `apps/web/node_modules/@tanstack/virtual-core` - ## @tauri-apps/api@2.11.1 - License: Apache-2.0 OR MIT @@ -492,22 +189,13 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@tauri-apps_plugin-deep-link@2.4.9` - Source package dir: `apps/tauri/node_modules/@tauri-apps/plugin-deep-link` -## @tauri-apps/plugin-log@2.8.0 - -- License: MIT OR Apache-2.0 -- Repository: https://github.com/tauri-apps/plugins-workspace -- Description: Configurable logging for your Tauri app. -- Included files: LICENSE.spdx -- Folder: `licenses/@tauri-apps_plugin-log@2.8.0` -- Source package dir: `apps/tauri/node_modules/@tauri-apps/plugin-log` - ## @tauri-apps/plugin-notification@2.3.3 - License: MIT OR Apache-2.0 - Repository: https://github.com/tauri-apps/plugins-workspace - Included files: LICENSE.spdx - Folder: `licenses/@tauri-apps_plugin-notification@2.3.3` -- Source package dir: `apps/tauri/node_modules/@tauri-apps/plugin-notification` +- Source package dir: `packages/notifications/node_modules/@tauri-apps/plugin-notification` ## @twemoji/api@17.0.3 @@ -519,14 +207,14 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@twemoji_api@17.0.3` - Source package dir: `packages/markdown/node_modules/@twemoji/api` -## @types/node@25.9.4 +## @types/node@26.2.0 - License: MIT - Homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node - Repository: https://github.com/DefinitelyTyped/DefinitelyTyped.git - Description: TypeScript definitions for node - Included files: LICENSE -- Folder: `licenses/@types_node@25.9.4` +- Folder: `licenses/@types_node@26.2.0` - Source package dir: `apps/electron/node_modules/@types/node` ## @types/qrcode@1.5.6 @@ -539,211 +227,46 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@types_qrcode@1.5.6` - Source package dir: `apps/web/node_modules/@types/qrcode` -## @types/react@19.2.17 +## @types/react@19.2.18 - License: MIT - Homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react - Repository: https://github.com/DefinitelyTyped/DefinitelyTyped.git - Description: TypeScript definitions for react - Included files: LICENSE -- Folder: `licenses/@types_react@19.2.17` +- Folder: `licenses/@types_react@19.2.18` - Source package dir: `apps/web/node_modules/@types/react` -## @types/react-dom@19.2.3 +## @types/react-dom@19.2.4 - License: MIT - Homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-dom - Repository: https://github.com/DefinitelyTyped/DefinitelyTyped.git - Description: TypeScript definitions for react-dom - Included files: LICENSE -- Folder: `licenses/@types_react-dom@19.2.3` +- Folder: `licenses/@types_react-dom@19.2.4` - Source package dir: `apps/web/node_modules/@types/react-dom` -## @typescript-eslint/parser@8.62.1 +## @typescript-eslint/parser@8.66.0 - License: MIT - Homepage: https://typescript-eslint.io/packages/parser - Repository: https://github.com/typescript-eslint/typescript-eslint.git - Description: An ESLint custom parser which leverages TypeScript ESTree - Included files: LICENSE -- Folder: `licenses/@typescript-eslint_parser@8.62.1` +- Folder: `licenses/@typescript-eslint_parser@8.66.0` - Source package dir: `node_modules/@typescript-eslint/parser` -## @vitejs/plugin-react@6.0.3 +## @vitejs/plugin-react@6.0.5 - License: MIT - Homepage: https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#readme - Repository: git+https://github.com/vitejs/vite-plugin-react.git - Description: The default Vite plugin for React projects - Included files: LICENSE -- Folder: `licenses/@vitejs_plugin-react@6.0.3` +- Folder: `licenses/@vitejs_plugin-react@6.0.5` - Source package dir: `apps/web/node_modules/@vitejs/plugin-react` -## aria-hidden@1.2.6 - -- License: MIT -- Homepage: https://github.com/theKashey/aria-hidden#readme -- Repository: git+https://github.com/theKashey/aria-hidden.git -- Description: Cast aria-hidden to everything, except... -- Included files: LICENSE -- Folder: `licenses/aria-hidden@1.2.6` -- Source package dir: `apps/web/node_modules/aria-hidden` - -## class-variance-authority@0.7.1 - -- License: Apache-2.0 -- Homepage: https://github.com/joe-bell/cva#readme -- Repository: https://github.com/joe-bell/cva.git -- Description: Class Variance Authority 🧬 -- Included files: LICENSE -- Folder: `licenses/class-variance-authority@0.7.1` -- Source package dir: `apps/web/node_modules/class-variance-authority` - -## clsx@2.1.1 - -- License: MIT -- Repository: lukeed/clsx -- Description: A tiny (239B) utility for constructing className strings conditionally. -- Included files: license -- Folder: `licenses/clsx@2.1.1` -- Source package dir: `apps/web/node_modules/clsx` - -## cmdk@1.1.1 - -- License: MIT -- Homepage: https://github.com/pacocoursey/cmdk#readme -- Repository: git+https://github.com/pacocoursey/cmdk.git -- Included files: LICENSE.md -- Folder: `licenses/cmdk@1.1.1` -- Source package dir: `apps/web/node_modules/cmdk` - -## cookie-es@3.1.1 - -- License: MIT -- Repository: unjs/cookie-es -- Included files: LICENSE -- Folder: `licenses/cookie-es@3.1.1` -- Source package dir: `apps/web/node_modules/cookie-es` - -## d3-array@3.2.4 - -- License: ISC -- Homepage: https://d3js.org/d3-array/ -- Repository: https://github.com/d3/d3-array.git -- Description: Array manipulation, ordering, searching, summarizing, etc. -- Included files: LICENSE -- Folder: `licenses/d3-array@3.2.4` -- Source package dir: `apps/web/node_modules/d3-array` - -## d3-color@3.1.0 - -- License: ISC -- Homepage: https://d3js.org/d3-color/ -- Repository: https://github.com/d3/d3-color.git -- Description: Color spaces! RGB, HSL, Cubehelix, Lab and HCL (Lch). -- Included files: LICENSE -- Folder: `licenses/d3-color@3.1.0` -- Source package dir: `apps/web/node_modules/d3-color` - -## d3-ease@3.0.1 - -- License: BSD-3-Clause -- Homepage: https://d3js.org/d3-ease/ -- Repository: https://github.com/d3/d3-ease.git -- Description: Easing functions for smooth animation. -- Included files: LICENSE -- Folder: `licenses/d3-ease@3.0.1` -- Source package dir: `apps/web/node_modules/d3-ease` - -## d3-format@3.1.2 - -- License: ISC -- Homepage: https://d3js.org/d3-format/ -- Repository: https://github.com/d3/d3-format.git -- Description: Format numbers for human consumption. -- Included files: LICENSE -- Folder: `licenses/d3-format@3.1.2` -- Source package dir: `apps/web/node_modules/d3-format` - -## d3-interpolate@3.0.1 - -- License: ISC -- Homepage: https://d3js.org/d3-interpolate/ -- Repository: https://github.com/d3/d3-interpolate.git -- Description: Interpolate numbers, colors, strings, arrays, objects, whatever! -- Included files: LICENSE -- Folder: `licenses/d3-interpolate@3.0.1` -- Source package dir: `apps/web/node_modules/d3-interpolate` - -## d3-path@3.1.0 - -- License: ISC -- Homepage: https://d3js.org/d3-path/ -- Repository: https://github.com/d3/d3-path.git -- Description: Serialize Canvas path commands to SVG. -- Included files: LICENSE -- Folder: `licenses/d3-path@3.1.0` -- Source package dir: `apps/web/node_modules/d3-path` - -## d3-scale@4.0.2 - -- License: ISC -- Homepage: https://d3js.org/d3-scale/ -- Repository: https://github.com/d3/d3-scale.git -- Description: Encodings that map abstract data to visual representation. -- Included files: LICENSE -- Folder: `licenses/d3-scale@4.0.2` -- Source package dir: `apps/web/node_modules/d3-scale` - -## d3-shape@3.2.0 - -- License: ISC -- Homepage: https://d3js.org/d3-shape/ -- Repository: https://github.com/d3/d3-shape.git -- Description: Graphical primitives for visualization, such as lines and areas. -- Included files: LICENSE -- Folder: `licenses/d3-shape@3.2.0` -- Source package dir: `apps/web/node_modules/d3-shape` - -## d3-time@3.1.0 - -- License: ISC -- Homepage: https://d3js.org/d3-time/ -- Repository: https://github.com/d3/d3-time.git -- Description: A calculator for humanity’s peculiar conventions of time. -- Included files: LICENSE -- Folder: `licenses/d3-time@3.1.0` -- Source package dir: `apps/web/node_modules/d3-time` - -## d3-time-format@4.1.0 - -- License: ISC -- Homepage: https://d3js.org/d3-time-format/ -- Repository: https://github.com/d3/d3-time-format.git -- Description: A JavaScript time formatter and parser inspired by strftime and strptime. -- Included files: LICENSE -- Folder: `licenses/d3-time-format@4.1.0` -- Source package dir: `apps/web/node_modules/d3-time-format` - -## d3-timer@3.0.1 - -- License: ISC -- Homepage: https://d3js.org/d3-timer/ -- Repository: https://github.com/d3/d3-timer.git -- Description: An efficient queue capable of managing thousands of concurrent animations. -- Included files: LICENSE -- Folder: `licenses/d3-timer@3.0.1` -- Source package dir: `apps/web/node_modules/d3-timer` - -## date-fns@4.4.0 - -- License: MIT -- Repository: https://github.com/date-fns/date-fns -- Description: Modern JavaScript date utility library -- Included files: LICENSE.md -- Folder: `licenses/date-fns@4.4.0` -- Source package dir: `apps/web/node_modules/date-fns` - ## decimal.js-light@2.5.1 - License: MIT @@ -763,33 +286,13 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/deepfilternet3-noise-filter@1.3.0` - Source package dir: `packages/call/node_modules/deepfilternet3-noise-filter` -## detect-node-es@1.1.0 - -- License: MIT -- Homepage: https://github.com/thekashey/detect-node -- Repository: https://github.com/thekashey/detect-node -- Description: Detect Node.JS (as opposite to browser environment). ESM modification -- Included files: LICENSE -- Folder: `licenses/detect-node-es@1.1.0` -- Source package dir: `apps/web/node_modules/detect-node-es` - -## dijkstrajs@1.0.3 - -- License: MIT -- Homepage: https://github.com/tcort/dijkstrajs -- Repository: git://github.com/tcort/dijkstrajs -- Description: A simple JavaScript implementation of Dijkstra's single-source shortest-paths algorithm. -- Included files: LICENSE.md -- Folder: `licenses/dijkstrajs@1.0.3` -- Source package dir: `apps/web/node_modules/dijkstrajs` - -## electron@39.8.10 +## electron@43.3.0 - License: MIT - Repository: https://github.com/electron/electron - Description: Build cross platform desktop apps with JavaScript, HTML, and CSS - Included files: LICENSE -- Folder: `licenses/electron@39.8.10` +- Folder: `licenses/electron@43.3.0` - Source package dir: `apps/electron/node_modules/electron` ## electron-builder@26.15.3 @@ -802,36 +305,6 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/electron-builder@26.15.3` - Source package dir: `apps/electron/node_modules/electron-builder` -## embla-carousel@8.6.0 - -- License: MIT -- Homepage: https://www.embla-carousel.com -- Repository: git+https://github.com/davidjerleke/embla-carousel -- Description: A lightweight carousel library with fluid motion and great swipe precision -- Included files: none found -- Folder: `licenses/embla-carousel@8.6.0` -- Source package dir: `apps/web/node_modules/embla-carousel` - -## embla-carousel-react@8.6.0 - -- License: MIT -- Homepage: https://www.embla-carousel.com -- Repository: git+https://github.com/davidjerleke/embla-carousel -- Description: A lightweight carousel library with fluid motion and great swipe precision -- Included files: none found -- Folder: `licenses/embla-carousel-react@8.6.0` -- Source package dir: `apps/web/node_modules/embla-carousel-react` - -## embla-carousel-reactive-utils@8.6.0 - -- License: MIT -- Homepage: https://www.embla-carousel.com -- Repository: git+https://github.com/davidjerleke/embla-carousel -- Description: Reactive utilities for Embla Carousel -- Included files: none found -- Folder: `licenses/embla-carousel-reactive-utils@8.6.0` -- Source package dir: `apps/web/node_modules/embla-carousel-reactive-utils` - ## emojibase-data@17.0.0 - License: MIT @@ -841,16 +314,6 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/emojibase-data@17.0.0` - Source package dir: `packages/markdown/node_modules/emojibase-data` -## es-toolkit@1.49.0 - -- License: MIT -- Homepage: https://es-toolkit.dev -- Repository: https://github.com/toss/es-toolkit.git -- Description: A state-of-the-art, high-performance JavaScript utility library with a small bundle size and strong type annotations. -- Included files: LICENSE -- Folder: `licenses/es-toolkit@1.49.0` -- Source package dir: `apps/web/node_modules/es-toolkit` - ## esbuild@0.28.1 - License: MIT @@ -860,14 +323,14 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/esbuild@0.28.1` - Source package dir: `apps/electron/node_modules/esbuild` -## eslint@10.6.0 +## eslint@10.8.1 - License: MIT - Homepage: https://eslint.org - Repository: eslint/eslint - Description: An AST-based pattern checker for JavaScript. - Included files: LICENSE -- Folder: `licenses/eslint@10.6.0` +- Folder: `licenses/eslint@10.8.1` - Source package dir: `apps/web/node_modules/eslint` ## eslint-plugin-react-hooks@7.1.1 @@ -889,100 +352,51 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/eventemitter3@5.0.4` - Source package dir: `apps/web/node_modules/eventemitter3` -## fallow@2.104.0 +## fallow@3.14.0 - License: MIT - Homepage: https://docs.fallow.tools - Repository: git+https://github.com/fallow-rs/fallow.git -- Description: Deterministic codebase intelligence for TypeScript and JavaScript. Quality, risk, architecture, dependencies, duplication, and safe cleanup evidence for humans, CI, and agents. Optional runtime intelligence layer (Fallow Runtime) adds production execution evidence. Rust-native, sub-second, zero-config framework support. +- Description: Codebase intelligence for TypeScript and JavaScript. Free static analysis of code and styles, optional paid runtime intelligence (Fallow Runtime). Quality, risk, architecture, dependencies, duplication, and design-system drift for humans, CI, and the agents writing your code. Zero-config framework support. - Included files: none found -- Folder: `licenses/fallow@2.104.0` +- Folder: `licenses/fallow@3.14.0` - Source package dir: `node_modules/fallow` -## get-nonce@1.0.1 - -- License: MIT -- Homepage: https://github.com/theKashey/get-nonce -- Repository: git@github.com:theKashey/get-nonce.git -- Description: returns nonce -- Included files: LICENSE -- Folder: `licenses/get-nonce@1.0.1` -- Source package dir: `apps/web/node_modules/get-nonce` - -## globals@17.7.0 +## globals@17.9.0 - License: MIT - Repository: sindresorhus/globals - Description: Global identifiers from different JavaScript environments - Included files: license -- Folder: `licenses/globals@17.7.0` +- Folder: `licenses/globals@17.9.0` - Source package dir: `apps/web/node_modules/globals` -## immer@10.2.0 - -- License: MIT -- Homepage: https://github.com/immerjs/immer#readme -- Repository: https://github.com/immerjs/immer.git -- Description: Create your next immutable state by mutating the current one -- Included files: LICENSE -- Folder: `licenses/immer@10.2.0` -- Source package dir: `apps/web/node_modules/immer` - -## input-otp@1.4.2 - -- License: MIT -- Homepage: https://input-otp.rodz.dev/ -- Repository: git+https://github.com/guilhermerodz/input-otp.git -- Description: One-time password input component for React. -- Included files: none found -- Folder: `licenses/input-otp@1.4.2` -- Source package dir: `apps/web/node_modules/input-otp` - -## internmap@2.0.3 - -- License: ISC -- Homepage: https://github.com/mbostock/internmap/ -- Repository: https://github.com/mbostock/internmap.git -- Description: Map and Set with automatic key interning -- Included files: LICENSE -- Folder: `licenses/internmap@2.0.3` -- Source package dir: `apps/web/node_modules/internmap` - -## jsonc-parser@3.3.1 - -- License: MIT -- Repository: https://github.com/microsoft/node-jsonc-parser -- Description: Scanner and parser for JSON with comments. -- Included files: LICENSE.md -- Folder: `licenses/jsonc-parser@3.3.1` -- Source package dir: `node_modules/jsonc-parser` - -## livekit-client@2.20.0 +## livekit-client@2.21.0 - License: Apache-2.0 - Repository: git@github.com:livekit/client-sdk-js.git - Description: JavaScript/TypeScript client SDK for LiveKit - Included files: LICENSE -- Folder: `licenses/livekit-client@2.20.0` +- Folder: `licenses/livekit-client@2.21.0` - Source package dir: `packages/call/node_modules/livekit-client` -## lucide-react@1.23.0 +## lucide-react@1.30.0 - License: ISC - Homepage: https://lucide.dev - Repository: https://github.com/lucide-icons/lucide.git - Description: A Lucide icon library package for React applications. - Included files: LICENSE -- Folder: `licenses/lucide-react@1.23.0` +- Folder: `licenses/lucide-react@1.30.0` - Source package dir: `apps/web/node_modules/lucide-react` -## motion@12.42.2 +## motion@13.0.0 - License: MIT - Repository: https://github.com/motiondivision/motion - Description: An animation library for JavaScript and React. - Included files: LICENSE.md -- Folder: `licenses/motion@12.42.2` +- Folder: `licenses/motion@13.0.0` - Source package dir: `packages/chat/node_modules/motion` ## mtp@0.2.0 @@ -993,82 +407,44 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/mtp@0.2.0` - Source package dir: `packages/mtp/node_modules/mtp` -## next-themes@0.4.6 - -- License: MIT -- Repository: https://github.com/pacocoursey/next-themes.git -- Included files: license.md -- Folder: `licenses/next-themes@0.4.6` -- Source package dir: `apps/web/node_modules/next-themes` - -## pngjs@5.0.0 - -- License: MIT -- Homepage: https://github.com/lukeapage/pngjs -- Repository: git://github.com/lukeapage/pngjs.git -- Description: PNG encoder/decoder in pure JS, supporting any bit size & interlace, async & sync with full test suite. -- Included files: LICENSE -- Folder: `licenses/pngjs@5.0.0` -- Source package dir: `apps/web/node_modules/pngjs` - -## prettier@3.9.4 +## prettier@3.9.6 - License: MIT - Homepage: https://prettier.io - Repository: prettier/prettier - Description: Prettier is an opinionated code formatter - Included files: LICENSE -- Folder: `licenses/prettier@3.9.4` +- Folder: `licenses/prettier@3.9.6` - Source package dir: `node_modules/prettier` -## qrcode@1.5.4 - -- License: MIT -- Homepage: http://github.com/soldair/node-qrcode -- Repository: git://github.com/soldair/node-qrcode.git -- Description: QRCode / 2d Barcode api with both server side and client side support using canvas -- Included files: license -- Folder: `licenses/qrcode@1.5.4` -- Source package dir: `apps/web/node_modules/qrcode` - -## react@19.2.7 +## react@19.2.8 - License: MIT - Homepage: https://react.dev/ -- Repository: https://github.com/facebook/react.git +- Repository: https://github.com/react/react.git - Description: React is a JavaScript library for building user interfaces. - Included files: LICENSE -- Folder: `licenses/react@19.2.7` +- Folder: `licenses/react@19.2.8` - Source package dir: `apps/tauri/node_modules/react` -## react-day-picker@10.0.1 - -- License: MIT -- Homepage: https://daypicker.dev -- Repository: git+https://github.com/gpbl/react-day-picker.git -- Description: Customizable Date Picker for React -- Included files: LICENSE -- Folder: `licenses/react-day-picker@10.0.1` -- Source package dir: `apps/web/node_modules/react-day-picker` - -## react-dom@19.2.7 +## react-dom@19.2.8 - License: MIT - Homepage: https://react.dev/ -- Repository: https://github.com/facebook/react.git +- Repository: https://github.com/react/react.git - Description: React package for working with the DOM. - Included files: LICENSE -- Folder: `licenses/react-dom@19.2.7` +- Folder: `licenses/react-dom@19.2.8` - Source package dir: `apps/tauri/node_modules/react-dom` -## react-is@19.2.7 +## react-is@19.2.8 - License: MIT - Homepage: https://react.dev/ -- Repository: https://github.com/facebook/react.git +- Repository: https://github.com/react/react.git - Description: Brand checking of React Elements. - Included files: LICENSE -- Folder: `licenses/react-is@19.2.7` +- Folder: `licenses/react-is@19.2.8` - Source package dir: `apps/web/node_modules/react-is` ## react-redux@9.3.0 @@ -1081,43 +457,6 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/react-redux@9.3.0` - Source package dir: `apps/web/node_modules/react-redux` -## react-remove-scroll@2.7.2 - -- License: MIT -- Repository: https://github.com/theKashey/react-remove-scroll -- Description: Disables scroll outside of `children` node. -- Included files: LICENSE -- Folder: `licenses/react-remove-scroll@2.7.2` -- Source package dir: `apps/web/node_modules/react-remove-scroll` - -## react-remove-scroll-bar@2.3.8 - -- License: MIT -- Repository: https://github.com/theKashey/react-remove-scroll-bar -- Description: Removes body scroll without content _shake_ -- Included files: none found -- Folder: `licenses/react-remove-scroll-bar@2.3.8` -- Source package dir: `apps/web/node_modules/react-remove-scroll-bar` - -## react-resizable-panels@4.12.0 - -- License: MIT -- Homepage: https://react-resizable-panels.vercel.app/ -- Repository: https://github.com/bvaughn/react-resizable-panels.git -- Included files: LICENSE.md -- Folder: `licenses/react-resizable-panels@4.12.0` -- Source package dir: `apps/web/node_modules/react-resizable-panels` - -## react-style-singleton@2.2.3 - -- License: MIT -- Homepage: https://github.com/theKashey/react-style-singleton#readme -- Repository: https://github.com/theKashey/react-style-singleton -- Description: Just create a single stylesheet... -- Included files: LICENSE -- Folder: `licenses/react-style-singleton@2.2.3` -- Source package dir: `apps/web/node_modules/react-style-singleton` - ## recharts@3.10.1 - License: MIT @@ -1126,75 +465,7 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Description: React charts - Included files: LICENSE - Folder: `licenses/recharts@3.10.1` -- Source package dir: `apps/web/node_modules/recharts` - -## redux@5.0.1 - -- License: MIT -- Homepage: http://redux.js.org -- Repository: github:reduxjs/redux -- Description: Predictable state container for JavaScript apps -- Included files: LICENSE.md -- Folder: `licenses/redux@5.0.1` -- Source package dir: `apps/web/node_modules/redux` - -## redux-thunk@3.1.0 - -- License: MIT -- Homepage: https://github.com/reduxjs/redux-thunk -- Repository: github:reduxjs/redux-thunk -- Description: Thunk middleware for Redux. -- Included files: LICENSE.md -- Folder: `licenses/redux-thunk@3.1.0` -- Source package dir: `apps/web/node_modules/redux-thunk` - -## reselect@5.1.1 - -- License: MIT -- Repository: https://github.com/reduxjs/reselect.git -- Description: Selectors for Redux. -- Included files: LICENSE -- Folder: `licenses/reselect@5.1.1` -- Source package dir: `apps/web/node_modules/reselect` - -## scheduler@0.27.0 - -- License: MIT -- Homepage: https://react.dev/ -- Repository: https://github.com/facebook/react.git -- Description: Cooperative scheduler for the browser environment. -- Included files: LICENSE -- Folder: `licenses/scheduler@0.27.0` -- Source package dir: `apps/web/node_modules/scheduler` - -## seroval@1.5.4 - -- License: MIT -- Homepage: https://github.com/lxsmnsyc/seroval/tree/main/packages/seroval -- Repository: https://github.com/lxsmnsyc/seroval.git -- Description: Stringify JS values -- Included files: LICENSE -- Folder: `licenses/seroval@1.5.4` -- Source package dir: `apps/web/node_modules/seroval` - -## seroval-plugins@1.5.4 - -- License: MIT -- Homepage: https://github.com/lxsmnsyc/seroval/tree/main/packages/plugins -- Repository: https://github.com/lxsmnsyc/seroval.git -- Description: Stringify JS values -- Included files: LICENSE -- Folder: `licenses/seroval-plugins@1.5.4` -- Source package dir: `apps/web/node_modules/seroval-plugins` - -## shadcn@4.12.0 - -- License: MIT -- Repository: https://github.com/shadcn-ui/ui.git -- Description: Add components to your apps. -- Included files: LICENSE.md -- Folder: `licenses/shadcn@4.12.0` -- Source package dir: `apps/web/node_modules/shadcn` +- Source package dir: `packages/call/node_modules/recharts` ## sonner@2.0.7 @@ -1204,17 +475,7 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Description: An opinionated toast component for React. - Included files: LICENSE.md - Folder: `licenses/sonner@2.0.7` -- Source package dir: `apps/web/node_modules/sonner` - -## tailwind-merge@3.6.0 - -- License: MIT -- Homepage: https://github.com/dcastil/tailwind-merge -- Repository: https://github.com/dcastil/tailwind-merge.git -- Description: Merge Tailwind CSS classes without style conflicts -- Included files: LICENSE.md -- Folder: `licenses/tailwind-merge@3.6.0` -- Source package dir: `apps/web/node_modules/tailwind-merge` +- Source package dir: `packages/notifications/node_modules/sonner` ## tailwind-scrollbar-hide@4.0.0 @@ -1226,35 +487,16 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/tailwind-scrollbar-hide@4.0.0` - Source package dir: `apps/web/node_modules/tailwind-scrollbar-hide` -## tailwindcss@4.3.2 +## tailwindcss@4.3.3 - License: MIT - Homepage: https://tailwindcss.com - Repository: https://github.com/tailwindlabs/tailwindcss.git - Description: A utility-first CSS framework for rapidly building custom user interfaces. - Included files: LICENSE -- Folder: `licenses/tailwindcss@4.3.2` +- Folder: `licenses/tailwindcss@4.3.3` - Source package dir: `apps/web/node_modules/tailwindcss` -## tiny-invariant@1.3.3 - -- License: MIT -- Repository: https://github.com/alexreardon/tiny-invariant.git -- Description: A tiny invariant function -- Included files: LICENSE -- Folder: `licenses/tiny-invariant@1.3.3` -- Source package dir: `apps/web/node_modules/tiny-invariant` - -## tslib@2.8.1 - -- License: 0BSD -- Homepage: https://www.typescriptlang.org/ -- Repository: https://github.com/Microsoft/tslib.git -- Description: Runtime library for TypeScript helper functions -- Included files: LICENSE.txt -- Folder: `licenses/tslib@2.8.1` -- Source package dir: `apps/web/node_modules/tslib` - ## tw-animate-css@1.4.0 - License: MIT @@ -1275,35 +517,16 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/typescript@6.0.3` - Source package dir: `apps/electron/node_modules/typescript` -## typescript-eslint@8.62.1 +## typescript-eslint@8.66.0 - License: MIT - Homepage: https://typescript-eslint.io/packages/typescript-eslint - Repository: https://github.com/typescript-eslint/typescript-eslint.git - Description: Tooling which enables you to use TypeScript with ESLint - Included files: LICENSE -- Folder: `licenses/typescript-eslint@8.62.1` +- Folder: `licenses/typescript-eslint@8.66.0` - Source package dir: `apps/web/node_modules/typescript-eslint` -## use-callback-ref@1.3.3 - -- License: MIT -- Repository: https://github.com/theKashey/use-callback-ref/ -- Description: The same useRef, but with callback -- Included files: LICENSE -- Folder: `licenses/use-callback-ref@1.3.3` -- Source package dir: `apps/web/node_modules/use-callback-ref` - -## use-sidecar@1.1.3 - -- License: MIT -- Homepage: https://github.com/theKashey/use-sidecar -- Repository: https://github.com/theKashey/use-sidecar -- Description: Sidecar code splitting utils -- Included files: LICENSE -- Folder: `licenses/use-sidecar@1.1.3` -- Source package dir: `apps/web/node_modules/use-sidecar` - ## use-sync-external-store@1.6.0 - License: MIT @@ -1313,66 +536,26 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/use-sync-external-store@1.6.0` - Source package dir: `apps/web/node_modules/use-sync-external-store` -## vaul@1.1.2 - -- License: MIT -- Homepage: https://vaul.emilkowal.ski/ -- Repository: https://github.com/emilkowalski/vaul.git -- Description: Drawer component for React. -- Included files: LICENSE.md -- Folder: `licenses/vaul@1.1.2` -- Source package dir: `apps/web/node_modules/vaul` - -## victory-vendor@37.3.6 - -- License: MIT AND ISC -- Homepage: https://commerce.nearform.com/open-source/victory -- Repository: https://github.com/FormidableLabs/victory -- Description: Vendored dependencies for Victory -- Included files: none found -- Folder: `licenses/victory-vendor@37.3.6` -- Source package dir: `apps/web/node_modules/victory-vendor` - -## vite@8.1.3 +## vite@8.2.1 - License: MIT - Homepage: https://vite.dev - Repository: git+https://github.com/vitejs/vite.git - Description: Native-ESM powered web dev build tool - Included files: LICENSE.md -- Folder: `licenses/vite@8.1.3` +- Folder: `licenses/vite@8.2.1` - Source package dir: `apps/web/node_modules/vite` -## vitest@4.1.9 +## vitest@4.1.10 - License: MIT - Homepage: https://vitest.dev - Repository: git+https://github.com/vitest-dev/vitest.git - Description: Next generation testing framework powered by Vite - Included files: LICENSE.md -- Folder: `licenses/vitest@4.1.9` +- Folder: `licenses/vitest@4.1.10` - Source package dir: `node_modules/vitest` -## yaml@2.9.0 - -- License: ISC -- Homepage: https://eemeli.org/yaml/ -- Repository: github:eemeli/yaml -- Description: JavaScript parser and stringifier for YAML -- Included files: LICENSE -- Folder: `licenses/yaml@2.9.0` -- Source package dir: `node_modules/yaml` - -## yargs@15.4.1 - -- License: MIT -- Homepage: https://yargs.js.org/ -- Repository: https://github.com/yargs/yargs.git -- Description: yargs the modern, pirate-themed, successor to optimist. -- Included files: LICENSE -- Folder: `licenses/yargs@15.4.1` -- Source package dir: `apps/web/node_modules/yargs` - ## zod@4.4.3 - License: MIT diff --git a/licenses/aria-hidden@1.2.6/LICENSE b/licenses/aria-hidden@1.2.6/LICENSE deleted file mode 100644 index a194c88..0000000 --- a/licenses/aria-hidden@1.2.6/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Anton Korzunov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/class-variance-authority@0.7.1/LICENSE b/licenses/class-variance-authority@0.7.1/LICENSE deleted file mode 100644 index 380ac71..0000000 --- a/licenses/class-variance-authority@0.7.1/LICENSE +++ /dev/null @@ -1,190 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2022 Joe Bell - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/licenses/clsx@2.1.1/license b/licenses/clsx@2.1.1/license deleted file mode 100644 index fa6089f..0000000 --- a/licenses/clsx@2.1.1/license +++ /dev/null @@ -1,9 +0,0 @@ -MIT License - -Copyright (c) Luke Edwards (lukeed.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/cmdk@1.1.1/LICENSE.md b/licenses/cmdk@1.1.1/LICENSE.md deleted file mode 100644 index 76228cc..0000000 --- a/licenses/cmdk@1.1.1/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 Paco Coursey - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/cookie-es@3.1.1/LICENSE b/licenses/cookie-es@3.1.1/LICENSE deleted file mode 100644 index db7eac1..0000000 --- a/licenses/cookie-es@3.1.1/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -MIT License - -Cookie-es copyright (c) Pooya Parsa - -Cookie parsing based on https://github.com/jshttp/cookie -Copyright (c) 2012-2014 Roman Shtylman -Copyright (c) 2015 Douglas Christopher Wilson - -Set-Cookie parsing based on https://github.com/nfriedly/set-cookie-parser -Copyright (c) 2015 Nathan Friedly (http://nfriedly.com/) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/d3-array@3.2.4/LICENSE b/licenses/d3-array@3.2.4/LICENSE deleted file mode 100644 index 3594fff..0000000 --- a/licenses/d3-array@3.2.4/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2010-2023 Mike Bostock - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/d3-color@3.1.0/LICENSE b/licenses/d3-color@3.1.0/LICENSE deleted file mode 100644 index fbe44bd..0000000 --- a/licenses/d3-color@3.1.0/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2010-2022 Mike Bostock - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/d3-ease@3.0.1/LICENSE b/licenses/d3-ease@3.0.1/LICENSE deleted file mode 100644 index 83cc997..0000000 --- a/licenses/d3-ease@3.0.1/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2010-2021 Mike Bostock -Copyright 2001 Robert Penner -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the author nor the names of contributors may be used to - endorse or promote products derived from this software without specific prior - written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/d3-format@3.1.2/LICENSE b/licenses/d3-format@3.1.2/LICENSE deleted file mode 100644 index a8918c4..0000000 --- a/licenses/d3-format@3.1.2/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2010-2026 Mike Bostock - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/d3-interpolate@3.0.1/LICENSE b/licenses/d3-interpolate@3.0.1/LICENSE deleted file mode 100644 index b014515..0000000 --- a/licenses/d3-interpolate@3.0.1/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2010-2021 Mike Bostock - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/d3-path@3.1.0/LICENSE b/licenses/d3-path@3.1.0/LICENSE deleted file mode 100644 index ed25746..0000000 --- a/licenses/d3-path@3.1.0/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2015-2022 Mike Bostock - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/d3-scale@4.0.2/LICENSE b/licenses/d3-scale@4.0.2/LICENSE deleted file mode 100644 index b014515..0000000 --- a/licenses/d3-scale@4.0.2/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2010-2021 Mike Bostock - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/d3-shape@3.2.0/LICENSE b/licenses/d3-shape@3.2.0/LICENSE deleted file mode 100644 index fbe44bd..0000000 --- a/licenses/d3-shape@3.2.0/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2010-2022 Mike Bostock - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/d3-time-format@4.1.0/LICENSE b/licenses/d3-time-format@4.1.0/LICENSE deleted file mode 100644 index b014515..0000000 --- a/licenses/d3-time-format@4.1.0/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2010-2021 Mike Bostock - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/d3-time@3.1.0/LICENSE b/licenses/d3-time@3.1.0/LICENSE deleted file mode 100644 index fbe44bd..0000000 --- a/licenses/d3-time@3.1.0/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2010-2022 Mike Bostock - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/d3-timer@3.0.1/LICENSE b/licenses/d3-timer@3.0.1/LICENSE deleted file mode 100644 index b014515..0000000 --- a/licenses/d3-timer@3.0.1/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2010-2021 Mike Bostock - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/date-fns@4.4.0/LICENSE.md b/licenses/date-fns@4.4.0/LICENSE.md deleted file mode 100644 index 29c6e85..0000000 --- a/licenses/date-fns@4.4.0/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Sasha Koss and Lesha Koss https://kossnocorp.mit-license.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/detect-node-es@1.1.0/LICENSE b/licenses/detect-node-es@1.1.0/LICENSE deleted file mode 100644 index 3113356..0000000 --- a/licenses/detect-node-es@1.1.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Ilya Kantor - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/dijkstrajs@1.0.3/LICENSE.md b/licenses/dijkstrajs@1.0.3/LICENSE.md deleted file mode 100644 index b662d80..0000000 --- a/licenses/dijkstrajs@1.0.3/LICENSE.md +++ /dev/null @@ -1,19 +0,0 @@ -``` -Dijkstra path-finding functions. Adapted from the Dijkstar Python project. - -Copyright (C) 2008 - Wyatt Baldwin - All rights reserved - -Licensed under the MIT license. - - http://www.opensource.org/licenses/mit-license.php - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -``` diff --git a/licenses/electron@39.8.10/LICENSE b/licenses/electron@43.3.0/LICENSE similarity index 100% rename from licenses/electron@39.8.10/LICENSE rename to licenses/electron@43.3.0/LICENSE diff --git a/licenses/es-toolkit@1.49.0/LICENSE b/licenses/es-toolkit@1.49.0/LICENSE deleted file mode 100644 index 69dc6a7..0000000 --- a/licenses/es-toolkit@1.49.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 Viva Republica, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/eslint@10.6.0/LICENSE b/licenses/eslint@10.8.1/LICENSE similarity index 100% rename from licenses/eslint@10.6.0/LICENSE rename to licenses/eslint@10.8.1/LICENSE diff --git a/licenses/get-nonce@1.0.1/LICENSE b/licenses/get-nonce@1.0.1/LICENSE deleted file mode 100644 index 9455bf5..0000000 --- a/licenses/get-nonce@1.0.1/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 Anton Korzunov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/globals@17.7.0/license b/licenses/globals@17.9.0/license similarity index 100% rename from licenses/globals@17.7.0/license rename to licenses/globals@17.9.0/license diff --git a/licenses/immer@10.2.0/LICENSE b/licenses/immer@10.2.0/LICENSE deleted file mode 100644 index c014115..0000000 --- a/licenses/immer@10.2.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Michel Weststrate - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/internmap@2.0.3/LICENSE b/licenses/internmap@2.0.3/LICENSE deleted file mode 100644 index 6fca711..0000000 --- a/licenses/internmap@2.0.3/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2021 Mike Bostock - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/jsonc-parser@3.3.1/LICENSE.md b/licenses/jsonc-parser@3.3.1/LICENSE.md deleted file mode 100644 index 1c65de1..0000000 --- a/licenses/jsonc-parser@3.3.1/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Microsoft - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/livekit-client@2.20.0/LICENSE b/licenses/livekit-client@2.21.0/LICENSE similarity index 100% rename from licenses/livekit-client@2.20.0/LICENSE rename to licenses/livekit-client@2.21.0/LICENSE diff --git a/licenses/lucide-react@1.23.0/LICENSE b/licenses/lucide-react@1.30.0/LICENSE similarity index 100% rename from licenses/lucide-react@1.23.0/LICENSE rename to licenses/lucide-react@1.30.0/LICENSE diff --git a/licenses/motion@12.42.2/LICENSE.md b/licenses/motion@13.0.0/LICENSE.md similarity index 100% rename from licenses/motion@12.42.2/LICENSE.md rename to licenses/motion@13.0.0/LICENSE.md diff --git a/licenses/next-themes@0.4.6/license.md b/licenses/next-themes@0.4.6/license.md deleted file mode 100644 index 76228cc..0000000 --- a/licenses/next-themes@0.4.6/license.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 Paco Coursey - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/pngjs@5.0.0/LICENSE b/licenses/pngjs@5.0.0/LICENSE deleted file mode 100644 index 6942e25..0000000 --- a/licenses/pngjs@5.0.0/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -pngjs2 original work Copyright (c) 2015 Luke Page & Original Contributors -pngjs derived work Copyright (c) 2012 Kuba Niegowski - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/licenses/prettier@3.9.4/LICENSE b/licenses/prettier@3.9.6/LICENSE similarity index 100% rename from licenses/prettier@3.9.4/LICENSE rename to licenses/prettier@3.9.6/LICENSE diff --git a/licenses/qrcode@1.5.4/license b/licenses/qrcode@1.5.4/license deleted file mode 100644 index 4e2b3b9..0000000 --- a/licenses/qrcode@1.5.4/license +++ /dev/null @@ -1,10 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2012 Ryan Day - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/licenses/react-day-picker@10.0.1/LICENSE b/licenses/react-day-picker@10.0.1/LICENSE deleted file mode 100644 index 07372a1..0000000 --- a/licenses/react-day-picker@10.0.1/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014-2026 Giampaolo Bellavite and contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/react-dom@19.2.7/LICENSE b/licenses/react-dom@19.2.8/LICENSE similarity index 100% rename from licenses/react-dom@19.2.7/LICENSE rename to licenses/react-dom@19.2.8/LICENSE diff --git a/licenses/react-is@19.2.7/LICENSE b/licenses/react-is@19.2.8/LICENSE similarity index 100% rename from licenses/react-is@19.2.7/LICENSE rename to licenses/react-is@19.2.8/LICENSE diff --git a/licenses/react-remove-scroll@2.7.2/LICENSE b/licenses/react-remove-scroll@2.7.2/LICENSE deleted file mode 100644 index a194c88..0000000 --- a/licenses/react-remove-scroll@2.7.2/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Anton Korzunov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/react-resizable-panels@4.12.0/LICENSE.md b/licenses/react-resizable-panels@4.12.0/LICENSE.md deleted file mode 100644 index 0569d0a..0000000 --- a/licenses/react-resizable-panels@4.12.0/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 Brian Vaughn - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/react-style-singleton@2.2.3/LICENSE b/licenses/react-style-singleton@2.2.3/LICENSE deleted file mode 100644 index a194c88..0000000 --- a/licenses/react-style-singleton@2.2.3/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Anton Korzunov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/react@19.2.7/LICENSE b/licenses/react@19.2.8/LICENSE similarity index 100% rename from licenses/react@19.2.7/LICENSE rename to licenses/react@19.2.8/LICENSE diff --git a/licenses/redux-thunk@3.1.0/LICENSE.md b/licenses/redux-thunk@3.1.0/LICENSE.md deleted file mode 100644 index c108bf3..0000000 --- a/licenses/redux-thunk@3.1.0/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015-present Dan Abramov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/redux@5.0.1/LICENSE.md b/licenses/redux@5.0.1/LICENSE.md deleted file mode 100644 index 55bc8df..0000000 --- a/licenses/redux@5.0.1/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015-present Dan Abramov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/reselect@5.1.1/LICENSE b/licenses/reselect@5.1.1/LICENSE deleted file mode 100644 index 2a957b4..0000000 --- a/licenses/reselect@5.1.1/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015-2018 Reselect Contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/sbom.cyclonedx.json b/licenses/sbom.cyclonedx.json index d8c89d9..4075c6b 100644 --- a/licenses/sbom.cyclonedx.json +++ b/licenses/sbom.cyclonedx.json @@ -3,7 +3,7 @@ "specVersion": "1.5", "version": 1, "metadata": { - "timestamp": "2026-08-06T09:49:26.512Z", + "timestamp": "2026-08-09T18:16:10.177Z", "tools": [ { "vendor": "OpenAI", @@ -16,107 +16,6 @@ } }, "components": [ - { - "type": "library", - "bomRef": "pkg:npm/%40babel/runtime@7.29.7", - "name": "@babel/runtime", - "version": "7.29.7", - "purl": "pkg:npm/%40babel/runtime@7.29.7", - "description": "babel's modular runtime helpers", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://babel.dev/docs/en/next/babel-runtime" - }, - { - "type": "vcs", - "url": "https://github.com/babel/babel.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@babel_runtime@7.29.7" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@babel/runtime" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40base-ui/react@1.6.0", - "name": "@base-ui/react", - "version": "1.6.0", - "purl": "pkg:npm/%40base-ui/react@1.6.0", - "description": "Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://base-ui.com" - }, - { - "type": "vcs", - "url": "git+https://github.com/mui/base-ui.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@base-ui_react@1.6.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@base-ui/react" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40base-ui/utils@0.3.2", - "name": "@base-ui/utils", - "version": "0.3.2", - "purl": "pkg:npm/%40base-ui/utils@0.3.2", - "description": "A collection of React utility functions for Base UI.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "git+https://github.com/mui/base-ui.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@base-ui_utils@0.3.2" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@base-ui/utils" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/%40codemirror/autocomplete@6.20.3", @@ -181,10 +80,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40codemirror/lang-markdown@6.5.0", + "bomRef": "pkg:npm/%40codemirror/lang-markdown@6.5.2", "name": "@codemirror/lang-markdown", - "version": "6.5.0", - "purl": "pkg:npm/%40codemirror/lang-markdown@6.5.0", + "version": "6.5.2", + "purl": "pkg:npm/%40codemirror/lang-markdown@6.5.2", "description": "Markdown language support for the CodeMirror code editor", "licenses": [ { @@ -196,13 +95,13 @@ "externalReferences": [ { "type": "vcs", - "url": "https://github.com/codemirror/lang-markdown.git" + "url": "git+https://code.haverbeke.berlin/codemirror/lang-markdown.git" } ], "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@codemirror_lang-markdown@6.5.0" + "value": "licenses/@codemirror_lang-markdown@6.5.2" }, { "name": "local:sourcePackageDir", @@ -243,10 +142,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40codemirror/state@6.7.0", + "bomRef": "pkg:npm/%40codemirror/state@6.7.1", "name": "@codemirror/state", - "version": "6.7.0", - "purl": "pkg:npm/%40codemirror/state@6.7.0", + "version": "6.7.1", + "purl": "pkg:npm/%40codemirror/state@6.7.1", "description": "Editor state data structures for the CodeMirror code editor", "licenses": [ { @@ -264,7 +163,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@codemirror_state@6.7.0" + "value": "licenses/@codemirror_state@6.7.1" }, { "name": "local:sourcePackageDir", @@ -274,10 +173,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40codemirror/view@6.43.4", + "bomRef": "pkg:npm/%40codemirror/view@6.43.8", "name": "@codemirror/view", - "version": "6.43.4", - "purl": "pkg:npm/%40codemirror/view@6.43.4", + "version": "6.43.8", + "purl": "pkg:npm/%40codemirror/view@6.43.8", "description": "DOM view component for the CodeMirror code editor", "licenses": [ { @@ -295,7 +194,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@codemirror_view@6.43.4" + "value": "licenses/@codemirror_view@6.43.8" }, { "name": "local:sourcePackageDir", @@ -340,185 +239,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40floating-ui/core@1.7.5", - "name": "@floating-ui/core", - "version": "1.7.5", - "purl": "pkg:npm/%40floating-ui/core@1.7.5", - "description": "Positioning library for floating elements: tooltips, popovers, dropdowns, and more", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://floating-ui.com" - }, - { - "type": "vcs", - "url": "https://github.com/floating-ui/floating-ui.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@floating-ui_core@1.7.5" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@floating-ui/core" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40floating-ui/dom@1.7.6", - "name": "@floating-ui/dom", - "version": "1.7.6", - "purl": "pkg:npm/%40floating-ui/dom@1.7.6", - "description": "Floating UI for the web", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://floating-ui.com" - }, - { - "type": "vcs", - "url": "https://github.com/floating-ui/floating-ui.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@floating-ui_dom@1.7.6" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@floating-ui/dom" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40floating-ui/react-dom@2.1.8", - "name": "@floating-ui/react-dom", - "version": "2.1.8", - "purl": "pkg:npm/%40floating-ui/react-dom@2.1.8", - "description": "Floating UI for React DOM", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://floating-ui.com/docs/react-dom" - }, - { - "type": "vcs", - "url": "https://github.com/floating-ui/floating-ui.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@floating-ui_react-dom@2.1.8" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@floating-ui/react-dom" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40floating-ui/utils@0.2.11", - "name": "@floating-ui/utils", - "version": "0.2.11", - "purl": "pkg:npm/%40floating-ui/utils@0.2.11", - "description": "Utilities for Floating UI", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://floating-ui.com" - }, - { - "type": "vcs", - "url": "https://github.com/floating-ui/floating-ui.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@floating-ui_utils@0.2.11" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@floating-ui/utils" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40fontsource-variable/inter@5.2.8", - "name": "@fontsource-variable/inter", - "version": "5.2.8", - "purl": "pkg:npm/%40fontsource-variable/inter@5.2.8", - "description": "Self-host the Inter font in a neatly bundled NPM package.", - "licenses": [ - { - "license": { - "id": "OFL-1.1" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://fontsource.org/fonts/inter" - }, - { - "type": "vcs", - "url": "git+https://github.com/fontsource/font-files.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@fontsource-variable_inter@5.2.8" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@fontsource-variable/inter" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40fontsource-variable/public-sans@5.2.7", + "bomRef": "pkg:npm/%40fontsource-variable/public-sans@5.3.0", "name": "@fontsource-variable/public-sans", - "version": "5.2.7", - "purl": "pkg:npm/%40fontsource-variable/public-sans@5.2.7", + "version": "5.3.0", + "purl": "pkg:npm/%40fontsource-variable/public-sans@5.3.0", "description": "Self-host the Public Sans font in a neatly bundled NPM package.", "licenses": [ { @@ -540,7 +264,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@fontsource-variable_public-sans@5.2.7" + "value": "licenses/@fontsource-variable_public-sans@5.3.0" }, { "name": "local:sourcePackageDir", @@ -550,10 +274,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40livekit/components-react@2.9.21", + "bomRef": "pkg:npm/%40livekit/components-react@2.9.23", "name": "@livekit/components-react", - "version": "2.9.21", - "purl": "pkg:npm/%40livekit/components-react@2.9.21", + "version": "2.9.23", + "purl": "pkg:npm/%40livekit/components-react@2.9.23", "licenses": [ { "license": { @@ -570,7 +294,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@livekit_components-react@2.9.21" + "value": "licenses/@livekit_components-react@2.9.23" }, { "name": "local:sourcePackageDir", @@ -598,589 +322,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40radix-ui/primitive@1.1.4", - "name": "@radix-ui/primitive", - "version": "1.1.4", - "purl": "pkg:npm/%40radix-ui/primitive@1.1.4", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_primitive@1.1.4" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/primitive" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-compose-refs@1.1.3", - "name": "@radix-ui/react-compose-refs", - "version": "1.1.3", - "purl": "pkg:npm/%40radix-ui/react-compose-refs@1.1.3", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-compose-refs@1.1.3" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-compose-refs" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-context@1.1.4", - "name": "@radix-ui/react-context", - "version": "1.1.4", - "purl": "pkg:npm/%40radix-ui/react-context@1.1.4", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-context@1.1.4" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-context" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-dialog@1.1.18", - "name": "@radix-ui/react-dialog", - "version": "1.1.18", - "purl": "pkg:npm/%40radix-ui/react-dialog@1.1.18", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-dialog@1.1.18" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-dialog" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-dismissable-layer@1.1.14", - "name": "@radix-ui/react-dismissable-layer", - "version": "1.1.14", - "purl": "pkg:npm/%40radix-ui/react-dismissable-layer@1.1.14", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-dismissable-layer@1.1.14" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-dismissable-layer" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-focus-guards@1.1.4", - "name": "@radix-ui/react-focus-guards", - "version": "1.1.4", - "purl": "pkg:npm/%40radix-ui/react-focus-guards@1.1.4", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-focus-guards@1.1.4" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-focus-guards" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-focus-scope@1.1.11", - "name": "@radix-ui/react-focus-scope", - "version": "1.1.11", - "purl": "pkg:npm/%40radix-ui/react-focus-scope@1.1.11", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-focus-scope@1.1.11" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-focus-scope" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-id@1.1.2", - "name": "@radix-ui/react-id", - "version": "1.1.2", - "purl": "pkg:npm/%40radix-ui/react-id@1.1.2", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-id@1.1.2" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-id" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-portal@1.1.13", - "name": "@radix-ui/react-portal", - "version": "1.1.13", - "purl": "pkg:npm/%40radix-ui/react-portal@1.1.13", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-portal@1.1.13" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-portal" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-presence@1.1.6", - "name": "@radix-ui/react-presence", - "version": "1.1.6", - "purl": "pkg:npm/%40radix-ui/react-presence@1.1.6", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-presence@1.1.6" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-presence" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-primitive@2.1.7", - "name": "@radix-ui/react-primitive", - "version": "2.1.7", - "purl": "pkg:npm/%40radix-ui/react-primitive@2.1.7", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-primitive@2.1.7" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-primitive" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-slot@1.3.0", - "name": "@radix-ui/react-slot", - "version": "1.3.0", - "purl": "pkg:npm/%40radix-ui/react-slot@1.3.0", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-slot@1.3.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-slot" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-use-callback-ref@1.1.2", - "name": "@radix-ui/react-use-callback-ref", - "version": "1.1.2", - "purl": "pkg:npm/%40radix-ui/react-use-callback-ref@1.1.2", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-use-callback-ref@1.1.2" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-use-callback-ref" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-use-controllable-state@1.2.3", - "name": "@radix-ui/react-use-controllable-state", - "version": "1.2.3", - "purl": "pkg:npm/%40radix-ui/react-use-controllable-state@1.2.3", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-use-controllable-state@1.2.3" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-use-controllable-state" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-use-effect-event@0.0.5", - "name": "@radix-ui/react-use-effect-event", - "version": "0.0.5", - "purl": "pkg:npm/%40radix-ui/react-use-effect-event@0.0.5", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-use-effect-event@0.0.5" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-use-effect-event" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40radix-ui/react-use-layout-effect@1.1.2", - "name": "@radix-ui/react-use-layout-effect", - "version": "1.1.2", - "purl": "pkg:npm/%40radix-ui/react-use-layout-effect@1.1.2", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://radix-ui.com/primitives" - }, - { - "type": "vcs", - "url": "git+https://github.com/radix-ui/primitives.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@radix-ui_react-use-layout-effect@1.1.2" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@radix-ui/react-use-layout-effect" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40reduxjs/toolkit@2.12.0", - "name": "@reduxjs/toolkit", - "version": "2.12.0", - "purl": "pkg:npm/%40reduxjs/toolkit@2.12.0", - "description": "The official, opinionated, batteries-included toolset for efficient Redux development", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://redux-toolkit.js.org" - }, - { - "type": "vcs", - "url": "git+https://github.com/reduxjs/redux-toolkit.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@reduxjs_toolkit@2.12.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@reduxjs/toolkit" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40tailwindcss/vite@4.3.2", + "bomRef": "pkg:npm/%40tailwindcss/vite@4.3.3", "name": "@tailwindcss/vite", - "version": "4.3.2", - "purl": "pkg:npm/%40tailwindcss/vite@4.3.2", + "version": "4.3.3", + "purl": "pkg:npm/%40tailwindcss/vite@4.3.3", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "licenses": [ { @@ -1202,7 +347,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@tailwindcss_vite@4.3.2" + "value": "licenses/@tailwindcss_vite@4.3.3" }, { "name": "local:sourcePackageDir", @@ -1210,76 +355,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/%40tanstack/devtools-event-client@0.5.0", - "name": "@tanstack/devtools-event-client", - "version": "0.5.0", - "purl": "pkg:npm/%40tanstack/devtools-event-client@0.5.0", - "description": "TanStack Event Client is a lightweight event client for TanStack Devtools event bus.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://tanstack.com/devtools" - }, - { - "type": "vcs", - "url": "git+https://github.com/TanStack/devtools.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@tanstack_devtools-event-client@0.5.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@tanstack/devtools-event-client" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40tanstack/history@1.162.0", - "name": "@tanstack/history", - "version": "1.162.0", - "purl": "pkg:npm/%40tanstack/history@1.162.0", - "description": "Modern and scalable routing for React applications", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://tanstack.com/router" - }, - { - "type": "vcs", - "url": "git+https://github.com/TanStack/router.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@tanstack_history@1.162.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@tanstack/history" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/%40tanstack/pacer@0.21.1", @@ -1315,41 +390,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/%40tanstack/query-core@5.101.2", - "name": "@tanstack/query-core", - "version": "5.101.2", - "purl": "pkg:npm/%40tanstack/query-core@5.101.2", - "description": "The framework agnostic core that powers TanStack Query", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://tanstack.com/query" - }, - { - "type": "vcs", - "url": "git+https://github.com/TanStack/query.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@tanstack_query-core@5.101.2" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@tanstack/query-core" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/%40tanstack/react-hotkeys@0.10.0", @@ -1387,10 +427,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40tanstack/react-query@5.101.2", + "bomRef": "pkg:npm/%40tanstack/react-query@5.101.4", "name": "@tanstack/react-query", - "version": "5.101.2", - "purl": "pkg:npm/%40tanstack/react-query@5.101.2", + "version": "5.101.4", + "purl": "pkg:npm/%40tanstack/react-query@5.101.4", "description": "Hooks for managing, caching and syncing asynchronous and remote data in React", "licenses": [ { @@ -1412,7 +452,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@tanstack_react-query@5.101.2" + "value": "licenses/@tanstack_react-query@5.101.4" }, { "name": "local:sourcePackageDir", @@ -1422,10 +462,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40tanstack/react-router@1.170.17", + "bomRef": "pkg:npm/%40tanstack/react-router@1.170.23", "name": "@tanstack/react-router", - "version": "1.170.17", - "purl": "pkg:npm/%40tanstack/react-router@1.170.17", + "version": "1.170.23", + "purl": "pkg:npm/%40tanstack/react-router@1.170.23", "description": "Modern and scalable routing for React applications", "licenses": [ { @@ -1447,7 +487,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@tanstack_react-router@1.170.17" + "value": "licenses/@tanstack_react-router@1.170.23" }, { "name": "local:sourcePackageDir", @@ -1457,45 +497,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40tanstack/react-store@0.11.0", - "name": "@tanstack/react-store", - "version": "0.11.0", - "purl": "pkg:npm/%40tanstack/react-store@0.11.0", - "description": "Framework agnostic type-safe store w/ reactive framework adapters", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://tanstack.com/store" - }, - { - "type": "vcs", - "url": "https://github.com/TanStack/store.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@tanstack_react-store@0.11.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@tanstack/react-store" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40tanstack/react-virtual@3.14.5", + "bomRef": "pkg:npm/%40tanstack/react-virtual@3.14.9", "name": "@tanstack/react-virtual", - "version": "3.14.5", - "purl": "pkg:npm/%40tanstack/react-virtual@3.14.5", + "version": "3.14.9", + "purl": "pkg:npm/%40tanstack/react-virtual@3.14.9", "description": "Headless UI for virtualizing scrollable elements in React", "licenses": [ { @@ -1517,7 +522,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@tanstack_react-virtual@3.14.5" + "value": "licenses/@tanstack_react-virtual@3.14.9" }, { "name": "local:sourcePackageDir", @@ -1525,111 +530,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/%40tanstack/router-core@1.171.14", - "name": "@tanstack/router-core", - "version": "1.171.14", - "purl": "pkg:npm/%40tanstack/router-core@1.171.14", - "description": "Modern and scalable routing for React applications", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://tanstack.com/router" - }, - { - "type": "vcs", - "url": "git+https://github.com/TanStack/router.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@tanstack_router-core@1.171.14" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@tanstack/router-core" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40tanstack/store@0.11.0", - "name": "@tanstack/store", - "version": "0.11.0", - "purl": "pkg:npm/%40tanstack/store@0.11.0", - "description": "Framework agnostic type-safe store w/ reactive framework adapters", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://tanstack.com/store" - }, - { - "type": "vcs", - "url": "git+https://github.com/TanStack/store.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@tanstack_store@0.11.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@tanstack/store" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40tanstack/virtual-core@3.17.3", - "name": "@tanstack/virtual-core", - "version": "3.17.3", - "purl": "pkg:npm/%40tanstack/virtual-core@3.17.3", - "description": "Headless UI for virtualizing scrollable elements in TS/JS + Frameworks", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://tanstack.com/virtual" - }, - { - "type": "vcs", - "url": "git+https://github.com/TanStack/virtual.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@tanstack_virtual-core@3.17.3" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/@tanstack/virtual-core" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/%40tauri-apps/api@2.11.1", @@ -1762,37 +662,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/%40tauri-apps/plugin-log@2.8.0", - "name": "@tauri-apps/plugin-log", - "version": "2.8.0", - "purl": "pkg:npm/%40tauri-apps/plugin-log@2.8.0", - "description": "Configurable logging for your Tauri app.", - "licenses": [ - { - "license": { - "name": "MIT OR Apache-2.0" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/tauri-apps/plugins-workspace" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@tauri-apps_plugin-log@2.8.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/tauri/node_modules/@tauri-apps/plugin-log" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/%40tauri-apps/plugin-notification@2.3.3", @@ -1819,7 +688,7 @@ }, { "name": "local:sourcePackageDir", - "value": "apps/tauri/node_modules/@tauri-apps/plugin-notification" + "value": "packages/notifications/node_modules/@tauri-apps/plugin-notification" } ] }, @@ -1860,10 +729,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40types/node@25.9.4", + "bomRef": "pkg:npm/%40types/node@26.2.0", "name": "@types/node", - "version": "25.9.4", - "purl": "pkg:npm/%40types/node@25.9.4", + "version": "26.2.0", + "purl": "pkg:npm/%40types/node@26.2.0", "description": "TypeScript definitions for node", "licenses": [ { @@ -1885,7 +754,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@types_node@25.9.4" + "value": "licenses/@types_node@26.2.0" }, { "name": "local:sourcePackageDir", @@ -1930,10 +799,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40types/react@19.2.17", + "bomRef": "pkg:npm/%40types/react@19.2.18", "name": "@types/react", - "version": "19.2.17", - "purl": "pkg:npm/%40types/react@19.2.17", + "version": "19.2.18", + "purl": "pkg:npm/%40types/react@19.2.18", "description": "TypeScript definitions for react", "licenses": [ { @@ -1955,7 +824,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@types_react@19.2.17" + "value": "licenses/@types_react@19.2.18" }, { "name": "local:sourcePackageDir", @@ -1965,10 +834,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40types/react-dom@19.2.3", + "bomRef": "pkg:npm/%40types/react-dom@19.2.4", "name": "@types/react-dom", - "version": "19.2.3", - "purl": "pkg:npm/%40types/react-dom@19.2.3", + "version": "19.2.4", + "purl": "pkg:npm/%40types/react-dom@19.2.4", "description": "TypeScript definitions for react-dom", "licenses": [ { @@ -1990,7 +859,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@types_react-dom@19.2.3" + "value": "licenses/@types_react-dom@19.2.4" }, { "name": "local:sourcePackageDir", @@ -2000,10 +869,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40typescript-eslint/parser@8.62.1", + "bomRef": "pkg:npm/%40typescript-eslint/parser@8.66.0", "name": "@typescript-eslint/parser", - "version": "8.62.1", - "purl": "pkg:npm/%40typescript-eslint/parser@8.62.1", + "version": "8.66.0", + "purl": "pkg:npm/%40typescript-eslint/parser@8.66.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", "licenses": [ { @@ -2025,7 +894,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@typescript-eslint_parser@8.62.1" + "value": "licenses/@typescript-eslint_parser@8.66.0" }, { "name": "local:sourcePackageDir", @@ -2035,10 +904,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40vitejs/plugin-react@6.0.3", + "bomRef": "pkg:npm/%40vitejs/plugin-react@6.0.5", "name": "@vitejs/plugin-react", - "version": "6.0.3", - "purl": "pkg:npm/%40vitejs/plugin-react@6.0.3", + "version": "6.0.5", + "purl": "pkg:npm/%40vitejs/plugin-react@6.0.5", "description": "The default Vite plugin for React projects", "licenses": [ { @@ -2060,7 +929,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@vitejs_plugin-react@6.0.3" + "value": "licenses/@vitejs_plugin-react@6.0.5" }, { "name": "local:sourcePackageDir", @@ -2068,587 +937,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/aria-hidden@1.2.6", - "name": "aria-hidden", - "version": "1.2.6", - "purl": "pkg:npm/aria-hidden@1.2.6", - "description": "Cast aria-hidden to everything, except...", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/theKashey/aria-hidden#readme" - }, - { - "type": "vcs", - "url": "git+https://github.com/theKashey/aria-hidden.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/aria-hidden@1.2.6" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/aria-hidden" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/class-variance-authority@0.7.1", - "name": "class-variance-authority", - "version": "0.7.1", - "purl": "pkg:npm/class-variance-authority@0.7.1", - "description": "Class Variance Authority 🧬", - "licenses": [ - { - "license": { - "id": "Apache-2.0" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/joe-bell/cva#readme" - }, - { - "type": "vcs", - "url": "https://github.com/joe-bell/cva.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/class-variance-authority@0.7.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/class-variance-authority" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/clsx@2.1.1", - "name": "clsx", - "version": "2.1.1", - "purl": "pkg:npm/clsx@2.1.1", - "description": "A tiny (239B) utility for constructing className strings conditionally.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "lukeed/clsx" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/clsx@2.1.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/clsx" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/cmdk@1.1.1", - "name": "cmdk", - "version": "1.1.1", - "purl": "pkg:npm/cmdk@1.1.1", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/pacocoursey/cmdk#readme" - }, - { - "type": "vcs", - "url": "git+https://github.com/pacocoursey/cmdk.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/cmdk@1.1.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/cmdk" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/cookie-es@3.1.1", - "name": "cookie-es", - "version": "3.1.1", - "purl": "pkg:npm/cookie-es@3.1.1", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "unjs/cookie-es" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/cookie-es@3.1.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/cookie-es" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/d3-array@3.2.4", - "name": "d3-array", - "version": "3.2.4", - "purl": "pkg:npm/d3-array@3.2.4", - "description": "Array manipulation, ordering, searching, summarizing, etc.", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://d3js.org/d3-array/" - }, - { - "type": "vcs", - "url": "https://github.com/d3/d3-array.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/d3-array@3.2.4" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/d3-array" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/d3-color@3.1.0", - "name": "d3-color", - "version": "3.1.0", - "purl": "pkg:npm/d3-color@3.1.0", - "description": "Color spaces! RGB, HSL, Cubehelix, Lab and HCL (Lch).", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://d3js.org/d3-color/" - }, - { - "type": "vcs", - "url": "https://github.com/d3/d3-color.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/d3-color@3.1.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/d3-color" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/d3-ease@3.0.1", - "name": "d3-ease", - "version": "3.0.1", - "purl": "pkg:npm/d3-ease@3.0.1", - "description": "Easing functions for smooth animation.", - "licenses": [ - { - "license": { - "id": "BSD-3-Clause" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://d3js.org/d3-ease/" - }, - { - "type": "vcs", - "url": "https://github.com/d3/d3-ease.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/d3-ease@3.0.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/d3-ease" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/d3-format@3.1.2", - "name": "d3-format", - "version": "3.1.2", - "purl": "pkg:npm/d3-format@3.1.2", - "description": "Format numbers for human consumption.", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://d3js.org/d3-format/" - }, - { - "type": "vcs", - "url": "https://github.com/d3/d3-format.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/d3-format@3.1.2" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/d3-format" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/d3-interpolate@3.0.1", - "name": "d3-interpolate", - "version": "3.0.1", - "purl": "pkg:npm/d3-interpolate@3.0.1", - "description": "Interpolate numbers, colors, strings, arrays, objects, whatever!", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://d3js.org/d3-interpolate/" - }, - { - "type": "vcs", - "url": "https://github.com/d3/d3-interpolate.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/d3-interpolate@3.0.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/d3-interpolate" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/d3-path@3.1.0", - "name": "d3-path", - "version": "3.1.0", - "purl": "pkg:npm/d3-path@3.1.0", - "description": "Serialize Canvas path commands to SVG.", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://d3js.org/d3-path/" - }, - { - "type": "vcs", - "url": "https://github.com/d3/d3-path.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/d3-path@3.1.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/d3-path" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/d3-scale@4.0.2", - "name": "d3-scale", - "version": "4.0.2", - "purl": "pkg:npm/d3-scale@4.0.2", - "description": "Encodings that map abstract data to visual representation.", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://d3js.org/d3-scale/" - }, - { - "type": "vcs", - "url": "https://github.com/d3/d3-scale.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/d3-scale@4.0.2" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/d3-scale" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/d3-shape@3.2.0", - "name": "d3-shape", - "version": "3.2.0", - "purl": "pkg:npm/d3-shape@3.2.0", - "description": "Graphical primitives for visualization, such as lines and areas.", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://d3js.org/d3-shape/" - }, - { - "type": "vcs", - "url": "https://github.com/d3/d3-shape.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/d3-shape@3.2.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/d3-shape" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/d3-time@3.1.0", - "name": "d3-time", - "version": "3.1.0", - "purl": "pkg:npm/d3-time@3.1.0", - "description": "A calculator for humanity’s peculiar conventions of time.", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://d3js.org/d3-time/" - }, - { - "type": "vcs", - "url": "https://github.com/d3/d3-time.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/d3-time@3.1.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/d3-time" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/d3-time-format@4.1.0", - "name": "d3-time-format", - "version": "4.1.0", - "purl": "pkg:npm/d3-time-format@4.1.0", - "description": "A JavaScript time formatter and parser inspired by strftime and strptime.", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://d3js.org/d3-time-format/" - }, - { - "type": "vcs", - "url": "https://github.com/d3/d3-time-format.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/d3-time-format@4.1.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/d3-time-format" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/d3-timer@3.0.1", - "name": "d3-timer", - "version": "3.0.1", - "purl": "pkg:npm/d3-timer@3.0.1", - "description": "An efficient queue capable of managing thousands of concurrent animations.", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://d3js.org/d3-timer/" - }, - { - "type": "vcs", - "url": "https://github.com/d3/d3-timer.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/d3-timer@3.0.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/d3-timer" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/date-fns@4.4.0", - "name": "date-fns", - "version": "4.4.0", - "purl": "pkg:npm/date-fns@4.4.0", - "description": "Modern JavaScript date utility library", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/date-fns/date-fns" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/date-fns@4.4.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/date-fns" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/decimal.js-light@2.5.1", @@ -2717,80 +1005,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/detect-node-es@1.1.0", - "name": "detect-node-es", - "version": "1.1.0", - "purl": "pkg:npm/detect-node-es@1.1.0", - "description": "Detect Node.JS (as opposite to browser environment). ESM modification", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/thekashey/detect-node" - }, - { - "type": "vcs", - "url": "https://github.com/thekashey/detect-node" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/detect-node-es@1.1.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/detect-node-es" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/dijkstrajs@1.0.3", - "name": "dijkstrajs", - "version": "1.0.3", - "purl": "pkg:npm/dijkstrajs@1.0.3", - "description": "A simple JavaScript implementation of Dijkstra's single-source shortest-paths algorithm.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/tcort/dijkstrajs" - }, - { - "type": "vcs", - "url": "git://github.com/tcort/dijkstrajs" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/dijkstrajs@1.0.3" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/dijkstrajs" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/electron@39.8.10", + "bomRef": "pkg:npm/electron@43.3.0", "name": "electron", - "version": "39.8.10", - "purl": "pkg:npm/electron@39.8.10", + "version": "43.3.0", + "purl": "pkg:npm/electron@43.3.0", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "licenses": [ { @@ -2808,7 +1026,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/electron@39.8.10" + "value": "licenses/electron@43.3.0" }, { "name": "local:sourcePackageDir", @@ -2851,111 +1069,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/embla-carousel@8.6.0", - "name": "embla-carousel", - "version": "8.6.0", - "purl": "pkg:npm/embla-carousel@8.6.0", - "description": "A lightweight carousel library with fluid motion and great swipe precision", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://www.embla-carousel.com" - }, - { - "type": "vcs", - "url": "git+https://github.com/davidjerleke/embla-carousel" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/embla-carousel@8.6.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/embla-carousel" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/embla-carousel-react@8.6.0", - "name": "embla-carousel-react", - "version": "8.6.0", - "purl": "pkg:npm/embla-carousel-react@8.6.0", - "description": "A lightweight carousel library with fluid motion and great swipe precision", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://www.embla-carousel.com" - }, - { - "type": "vcs", - "url": "git+https://github.com/davidjerleke/embla-carousel" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/embla-carousel-react@8.6.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/embla-carousel-react" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/embla-carousel-reactive-utils@8.6.0", - "name": "embla-carousel-reactive-utils", - "version": "8.6.0", - "purl": "pkg:npm/embla-carousel-reactive-utils@8.6.0", - "description": "Reactive utilities for Embla Carousel", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://www.embla-carousel.com" - }, - { - "type": "vcs", - "url": "git+https://github.com/davidjerleke/embla-carousel" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/embla-carousel-reactive-utils@8.6.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/embla-carousel-reactive-utils" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/emojibase-data@17.0.0", @@ -2987,41 +1100,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/es-toolkit@1.49.0", - "name": "es-toolkit", - "version": "1.49.0", - "purl": "pkg:npm/es-toolkit@1.49.0", - "description": "A state-of-the-art, high-performance JavaScript utility library with a small bundle size and strong type annotations.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://es-toolkit.dev" - }, - { - "type": "vcs", - "url": "https://github.com/toss/es-toolkit.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/es-toolkit@1.49.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/es-toolkit" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/esbuild@0.28.1", @@ -3055,10 +1133,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/eslint@10.6.0", + "bomRef": "pkg:npm/eslint@10.8.1", "name": "eslint", - "version": "10.6.0", - "purl": "pkg:npm/eslint@10.6.0", + "version": "10.8.1", + "purl": "pkg:npm/eslint@10.8.1", "description": "An AST-based pattern checker for JavaScript.", "licenses": [ { @@ -3080,7 +1158,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/eslint@10.6.0" + "value": "licenses/eslint@10.8.1" }, { "name": "local:sourcePackageDir", @@ -3156,11 +1234,11 @@ }, { "type": "library", - "bomRef": "pkg:npm/fallow@2.104.0", + "bomRef": "pkg:npm/fallow@3.14.0", "name": "fallow", - "version": "2.104.0", - "purl": "pkg:npm/fallow@2.104.0", - "description": "Deterministic codebase intelligence for TypeScript and JavaScript. Quality, risk, architecture, dependencies, duplication, and safe cleanup evidence for humans, CI, and agents. Optional runtime intelligence layer (Fallow Runtime) adds production execution evidence. Rust-native, sub-second, zero-config framework support.", + "version": "3.14.0", + "purl": "pkg:npm/fallow@3.14.0", + "description": "Codebase intelligence for TypeScript and JavaScript. Free static analysis of code and styles, optional paid runtime intelligence (Fallow Runtime). Quality, risk, architecture, dependencies, duplication, and design-system drift for humans, CI, and the agents writing your code. Zero-config framework support.", "licenses": [ { "license": { @@ -3181,7 +1259,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/fallow@2.104.0" + "value": "licenses/fallow@3.14.0" }, { "name": "local:sourcePackageDir", @@ -3191,45 +1269,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/get-nonce@1.0.1", - "name": "get-nonce", - "version": "1.0.1", - "purl": "pkg:npm/get-nonce@1.0.1", - "description": "returns nonce", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/theKashey/get-nonce" - }, - { - "type": "vcs", - "url": "git@github.com:theKashey/get-nonce.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/get-nonce@1.0.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/get-nonce" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/globals@17.7.0", + "bomRef": "pkg:npm/globals@17.9.0", "name": "globals", - "version": "17.7.0", - "purl": "pkg:npm/globals@17.7.0", + "version": "17.9.0", + "purl": "pkg:npm/globals@17.9.0", "description": "Global identifiers from different JavaScript environments", "licenses": [ { @@ -3247,7 +1290,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/globals@17.7.0" + "value": "licenses/globals@17.9.0" }, { "name": "local:sourcePackageDir", @@ -3257,146 +1300,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/immer@10.2.0", - "name": "immer", - "version": "10.2.0", - "purl": "pkg:npm/immer@10.2.0", - "description": "Create your next immutable state by mutating the current one", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/immerjs/immer#readme" - }, - { - "type": "vcs", - "url": "https://github.com/immerjs/immer.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/immer@10.2.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/immer" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/input-otp@1.4.2", - "name": "input-otp", - "version": "1.4.2", - "purl": "pkg:npm/input-otp@1.4.2", - "description": "One-time password input component for React.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://input-otp.rodz.dev/" - }, - { - "type": "vcs", - "url": "git+https://github.com/guilhermerodz/input-otp.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/input-otp@1.4.2" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/input-otp" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/internmap@2.0.3", - "name": "internmap", - "version": "2.0.3", - "purl": "pkg:npm/internmap@2.0.3", - "description": "Map and Set with automatic key interning", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/mbostock/internmap/" - }, - { - "type": "vcs", - "url": "https://github.com/mbostock/internmap.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/internmap@2.0.3" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/internmap" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/jsonc-parser@3.3.1", - "name": "jsonc-parser", - "version": "3.3.1", - "purl": "pkg:npm/jsonc-parser@3.3.1", - "description": "Scanner and parser for JSON with comments.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/microsoft/node-jsonc-parser" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/jsonc-parser@3.3.1" - }, - { - "name": "local:sourcePackageDir", - "value": "node_modules/jsonc-parser" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/livekit-client@2.20.0", + "bomRef": "pkg:npm/livekit-client@2.21.0", "name": "livekit-client", - "version": "2.20.0", - "purl": "pkg:npm/livekit-client@2.20.0", + "version": "2.21.0", + "purl": "pkg:npm/livekit-client@2.21.0", "description": "JavaScript/TypeScript client SDK for LiveKit", "licenses": [ { @@ -3414,7 +1321,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/livekit-client@2.20.0" + "value": "licenses/livekit-client@2.21.0" }, { "name": "local:sourcePackageDir", @@ -3424,10 +1331,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/lucide-react@1.23.0", + "bomRef": "pkg:npm/lucide-react@1.30.0", "name": "lucide-react", - "version": "1.23.0", - "purl": "pkg:npm/lucide-react@1.23.0", + "version": "1.30.0", + "purl": "pkg:npm/lucide-react@1.30.0", "description": "A Lucide icon library package for React applications.", "licenses": [ { @@ -3449,7 +1356,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/lucide-react@1.23.0" + "value": "licenses/lucide-react@1.30.0" }, { "name": "local:sourcePackageDir", @@ -3459,10 +1366,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/motion@12.42.2", + "bomRef": "pkg:npm/motion@13.0.0", "name": "motion", - "version": "12.42.2", - "purl": "pkg:npm/motion@12.42.2", + "version": "13.0.0", + "purl": "pkg:npm/motion@13.0.0", "description": "An animation library for JavaScript and React.", "licenses": [ { @@ -3480,7 +1387,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/motion@12.42.2" + "value": "licenses/motion@13.0.0" }, { "name": "local:sourcePackageDir", @@ -3509,75 +1416,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/next-themes@0.4.6", - "name": "next-themes", - "version": "0.4.6", - "purl": "pkg:npm/next-themes@0.4.6", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/pacocoursey/next-themes.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/next-themes@0.4.6" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/next-themes" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/pngjs@5.0.0", - "name": "pngjs", - "version": "5.0.0", - "purl": "pkg:npm/pngjs@5.0.0", - "description": "PNG encoder/decoder in pure JS, supporting any bit size & interlace, async & sync with full test suite.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/lukeapage/pngjs" - }, - { - "type": "vcs", - "url": "git://github.com/lukeapage/pngjs.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/pngjs@5.0.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/pngjs" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/prettier@3.9.4", + "bomRef": "pkg:npm/prettier@3.9.6", "name": "prettier", - "version": "3.9.4", - "purl": "pkg:npm/prettier@3.9.4", + "version": "3.9.6", + "purl": "pkg:npm/prettier@3.9.6", "description": "Prettier is an opinionated code formatter", "licenses": [ { @@ -3599,7 +1441,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/prettier@3.9.4" + "value": "licenses/prettier@3.9.6" }, { "name": "local:sourcePackageDir", @@ -3609,45 +1451,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/qrcode@1.5.4", - "name": "qrcode", - "version": "1.5.4", - "purl": "pkg:npm/qrcode@1.5.4", - "description": "QRCode / 2d Barcode api with both server side and client side support using canvas", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "http://github.com/soldair/node-qrcode" - }, - { - "type": "vcs", - "url": "git://github.com/soldair/node-qrcode.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/qrcode@1.5.4" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/qrcode" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/react@19.2.7", + "bomRef": "pkg:npm/react@19.2.8", "name": "react", - "version": "19.2.7", - "purl": "pkg:npm/react@19.2.7", + "version": "19.2.8", + "purl": "pkg:npm/react@19.2.8", "description": "React is a JavaScript library for building user interfaces.", "licenses": [ { @@ -3663,13 +1470,13 @@ }, { "type": "vcs", - "url": "https://github.com/facebook/react.git" + "url": "https://github.com/react/react.git" } ], "properties": [ { "name": "local:licenseFolder", - "value": "licenses/react@19.2.7" + "value": "licenses/react@19.2.8" }, { "name": "local:sourcePackageDir", @@ -3679,45 +1486,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/react-day-picker@10.0.1", - "name": "react-day-picker", - "version": "10.0.1", - "purl": "pkg:npm/react-day-picker@10.0.1", - "description": "Customizable Date Picker for React", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://daypicker.dev" - }, - { - "type": "vcs", - "url": "git+https://github.com/gpbl/react-day-picker.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/react-day-picker@10.0.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/react-day-picker" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/react-dom@19.2.7", + "bomRef": "pkg:npm/react-dom@19.2.8", "name": "react-dom", - "version": "19.2.7", - "purl": "pkg:npm/react-dom@19.2.7", + "version": "19.2.8", + "purl": "pkg:npm/react-dom@19.2.8", "description": "React package for working with the DOM.", "licenses": [ { @@ -3733,13 +1505,13 @@ }, { "type": "vcs", - "url": "https://github.com/facebook/react.git" + "url": "https://github.com/react/react.git" } ], "properties": [ { "name": "local:licenseFolder", - "value": "licenses/react-dom@19.2.7" + "value": "licenses/react-dom@19.2.8" }, { "name": "local:sourcePackageDir", @@ -3749,10 +1521,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/react-is@19.2.7", + "bomRef": "pkg:npm/react-is@19.2.8", "name": "react-is", - "version": "19.2.7", - "purl": "pkg:npm/react-is@19.2.7", + "version": "19.2.8", + "purl": "pkg:npm/react-is@19.2.8", "description": "Brand checking of React Elements.", "licenses": [ { @@ -3768,13 +1540,13 @@ }, { "type": "vcs", - "url": "https://github.com/facebook/react.git" + "url": "https://github.com/react/react.git" } ], "properties": [ { "name": "local:licenseFolder", - "value": "licenses/react-is@19.2.7" + "value": "licenses/react-is@19.2.8" }, { "name": "local:sourcePackageDir", @@ -3817,137 +1589,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/react-remove-scroll@2.7.2", - "name": "react-remove-scroll", - "version": "2.7.2", - "purl": "pkg:npm/react-remove-scroll@2.7.2", - "description": "Disables scroll outside of `children` node.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/theKashey/react-remove-scroll" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/react-remove-scroll@2.7.2" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/react-remove-scroll" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/react-remove-scroll-bar@2.3.8", - "name": "react-remove-scroll-bar", - "version": "2.3.8", - "purl": "pkg:npm/react-remove-scroll-bar@2.3.8", - "description": "Removes body scroll without content _shake_", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/theKashey/react-remove-scroll-bar" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/react-remove-scroll-bar@2.3.8" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/react-remove-scroll-bar" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/react-resizable-panels@4.12.0", - "name": "react-resizable-panels", - "version": "4.12.0", - "purl": "pkg:npm/react-resizable-panels@4.12.0", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://react-resizable-panels.vercel.app/" - }, - { - "type": "vcs", - "url": "https://github.com/bvaughn/react-resizable-panels.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/react-resizable-panels@4.12.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/react-resizable-panels" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/react-style-singleton@2.2.3", - "name": "react-style-singleton", - "version": "2.2.3", - "purl": "pkg:npm/react-style-singleton@2.2.3", - "description": "Just create a single stylesheet...", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/theKashey/react-style-singleton#readme" - }, - { - "type": "vcs", - "url": "https://github.com/theKashey/react-style-singleton" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/react-style-singleton@2.2.3" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/react-style-singleton" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/recharts@3.10.1", @@ -3979,244 +1620,7 @@ }, { "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/recharts" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/redux@5.0.1", - "name": "redux", - "version": "5.0.1", - "purl": "pkg:npm/redux@5.0.1", - "description": "Predictable state container for JavaScript apps", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "http://redux.js.org" - }, - { - "type": "vcs", - "url": "github:reduxjs/redux" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/redux@5.0.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/redux" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/redux-thunk@3.1.0", - "name": "redux-thunk", - "version": "3.1.0", - "purl": "pkg:npm/redux-thunk@3.1.0", - "description": "Thunk middleware for Redux.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/reduxjs/redux-thunk" - }, - { - "type": "vcs", - "url": "github:reduxjs/redux-thunk" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/redux-thunk@3.1.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/redux-thunk" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/reselect@5.1.1", - "name": "reselect", - "version": "5.1.1", - "purl": "pkg:npm/reselect@5.1.1", - "description": "Selectors for Redux.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/reduxjs/reselect.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/reselect@5.1.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/reselect" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/scheduler@0.27.0", - "name": "scheduler", - "version": "0.27.0", - "purl": "pkg:npm/scheduler@0.27.0", - "description": "Cooperative scheduler for the browser environment.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://react.dev/" - }, - { - "type": "vcs", - "url": "https://github.com/facebook/react.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/scheduler@0.27.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/scheduler" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/seroval@1.5.4", - "name": "seroval", - "version": "1.5.4", - "purl": "pkg:npm/seroval@1.5.4", - "description": "Stringify JS values", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/lxsmnsyc/seroval/tree/main/packages/seroval" - }, - { - "type": "vcs", - "url": "https://github.com/lxsmnsyc/seroval.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/seroval@1.5.4" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/seroval" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/seroval-plugins@1.5.4", - "name": "seroval-plugins", - "version": "1.5.4", - "purl": "pkg:npm/seroval-plugins@1.5.4", - "description": "Stringify JS values", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/lxsmnsyc/seroval/tree/main/packages/plugins" - }, - { - "type": "vcs", - "url": "https://github.com/lxsmnsyc/seroval.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/seroval-plugins@1.5.4" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/seroval-plugins" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/shadcn@4.12.0", - "name": "shadcn", - "version": "4.12.0", - "purl": "pkg:npm/shadcn@4.12.0", - "description": "Add components to your apps.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/shadcn-ui/ui.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/shadcn@4.12.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/shadcn" + "value": "packages/call/node_modules/recharts" } ] }, @@ -4251,42 +1655,7 @@ }, { "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/sonner" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/tailwind-merge@3.6.0", - "name": "tailwind-merge", - "version": "3.6.0", - "purl": "pkg:npm/tailwind-merge@3.6.0", - "description": "Merge Tailwind CSS classes without style conflicts", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/dcastil/tailwind-merge" - }, - { - "type": "vcs", - "url": "https://github.com/dcastil/tailwind-merge.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/tailwind-merge@3.6.0" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/tailwind-merge" + "value": "packages/notifications/node_modules/sonner" } ] }, @@ -4327,10 +1696,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/tailwindcss@4.3.2", + "bomRef": "pkg:npm/tailwindcss@4.3.3", "name": "tailwindcss", - "version": "4.3.2", - "purl": "pkg:npm/tailwindcss@4.3.2", + "version": "4.3.3", + "purl": "pkg:npm/tailwindcss@4.3.3", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "licenses": [ { @@ -4352,7 +1721,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/tailwindcss@4.3.2" + "value": "licenses/tailwindcss@4.3.3" }, { "name": "local:sourcePackageDir", @@ -4360,72 +1729,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/tiny-invariant@1.3.3", - "name": "tiny-invariant", - "version": "1.3.3", - "purl": "pkg:npm/tiny-invariant@1.3.3", - "description": "A tiny invariant function", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/alexreardon/tiny-invariant.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/tiny-invariant@1.3.3" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/tiny-invariant" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/tslib@2.8.1", - "name": "tslib", - "version": "2.8.1", - "purl": "pkg:npm/tslib@2.8.1", - "description": "Runtime library for TypeScript helper functions", - "licenses": [ - { - "license": { - "id": "0BSD" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://www.typescriptlang.org/" - }, - { - "type": "vcs", - "url": "https://github.com/Microsoft/tslib.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/tslib@2.8.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/tslib" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/tw-animate-css@1.4.0", @@ -4498,10 +1801,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/typescript-eslint@8.62.1", + "bomRef": "pkg:npm/typescript-eslint@8.66.0", "name": "typescript-eslint", - "version": "8.62.1", - "purl": "pkg:npm/typescript-eslint@8.62.1", + "version": "8.66.0", + "purl": "pkg:npm/typescript-eslint@8.66.0", "description": "Tooling which enables you to use TypeScript with ESLint", "licenses": [ { @@ -4523,7 +1826,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/typescript-eslint@8.62.1" + "value": "licenses/typescript-eslint@8.66.0" }, { "name": "local:sourcePackageDir", @@ -4531,72 +1834,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/use-callback-ref@1.3.3", - "name": "use-callback-ref", - "version": "1.3.3", - "purl": "pkg:npm/use-callback-ref@1.3.3", - "description": "The same useRef, but with callback", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/theKashey/use-callback-ref/" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/use-callback-ref@1.3.3" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/use-callback-ref" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/use-sidecar@1.1.3", - "name": "use-sidecar", - "version": "1.1.3", - "purl": "pkg:npm/use-sidecar@1.1.3", - "description": "Sidecar code splitting utils", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/theKashey/use-sidecar" - }, - { - "type": "vcs", - "url": "https://github.com/theKashey/use-sidecar" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/use-sidecar@1.1.3" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/use-sidecar" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/use-sync-external-store@1.6.0", @@ -4630,80 +1867,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/vaul@1.1.2", - "name": "vaul", - "version": "1.1.2", - "purl": "pkg:npm/vaul@1.1.2", - "description": "Drawer component for React.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://vaul.emilkowal.ski/" - }, - { - "type": "vcs", - "url": "https://github.com/emilkowalski/vaul.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/vaul@1.1.2" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/vaul" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/victory-vendor@37.3.6", - "name": "victory-vendor", - "version": "37.3.6", - "purl": "pkg:npm/victory-vendor@37.3.6", - "description": "Vendored dependencies for Victory", - "licenses": [ - { - "license": { - "name": "MIT AND ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://commerce.nearform.com/open-source/victory" - }, - { - "type": "vcs", - "url": "https://github.com/FormidableLabs/victory" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/victory-vendor@37.3.6" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/victory-vendor" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/vite@8.1.3", + "bomRef": "pkg:npm/vite@8.2.1", "name": "vite", - "version": "8.1.3", - "purl": "pkg:npm/vite@8.1.3", + "version": "8.2.1", + "purl": "pkg:npm/vite@8.2.1", "description": "Native-ESM powered web dev build tool", "licenses": [ { @@ -4725,7 +1892,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/vite@8.1.3" + "value": "licenses/vite@8.2.1" }, { "name": "local:sourcePackageDir", @@ -4735,10 +1902,10 @@ }, { "type": "library", - "bomRef": "pkg:npm/vitest@4.1.9", + "bomRef": "pkg:npm/vitest@4.1.10", "name": "vitest", - "version": "4.1.9", - "purl": "pkg:npm/vitest@4.1.9", + "version": "4.1.10", + "purl": "pkg:npm/vitest@4.1.10", "description": "Next generation testing framework powered by Vite", "licenses": [ { @@ -4760,7 +1927,7 @@ "properties": [ { "name": "local:licenseFolder", - "value": "licenses/vitest@4.1.9" + "value": "licenses/vitest@4.1.10" }, { "name": "local:sourcePackageDir", @@ -4768,76 +1935,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/yaml@2.9.0", - "name": "yaml", - "version": "2.9.0", - "purl": "pkg:npm/yaml@2.9.0", - "description": "JavaScript parser and stringifier for YAML", - "licenses": [ - { - "license": { - "id": "ISC" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://eemeli.org/yaml/" - }, - { - "type": "vcs", - "url": "github:eemeli/yaml" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/yaml@2.9.0" - }, - { - "name": "local:sourcePackageDir", - "value": "node_modules/yaml" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/yargs@15.4.1", - "name": "yargs", - "version": "15.4.1", - "purl": "pkg:npm/yargs@15.4.1", - "description": "yargs the modern, pirate-themed, successor to optimist.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://yargs.js.org/" - }, - { - "type": "vcs", - "url": "https://github.com/yargs/yargs.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/yargs@15.4.1" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/web/node_modules/yargs" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/zod@4.4.3", diff --git a/licenses/scheduler@0.27.0/LICENSE b/licenses/scheduler@0.27.0/LICENSE deleted file mode 100644 index b93be90..0000000 --- a/licenses/scheduler@0.27.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) Meta Platforms, Inc. and affiliates. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/seroval-plugins@1.5.4/LICENSE b/licenses/seroval-plugins@1.5.4/LICENSE deleted file mode 100644 index 78c9813..0000000 --- a/licenses/seroval-plugins@1.5.4/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -MIT License Copyright (c) 2025 Alexis Munsayac - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/licenses/seroval@1.5.4/LICENSE b/licenses/seroval@1.5.4/LICENSE deleted file mode 100644 index 78c9813..0000000 --- a/licenses/seroval@1.5.4/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -MIT License Copyright (c) 2025 Alexis Munsayac - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/licenses/shadcn@4.12.0/LICENSE.md b/licenses/shadcn@4.12.0/LICENSE.md deleted file mode 100644 index fad4d88..0000000 --- a/licenses/shadcn@4.12.0/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 shadcn - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/tailwind-merge@3.6.0/LICENSE.md b/licenses/tailwind-merge@3.6.0/LICENSE.md deleted file mode 100644 index 0d2b96a..0000000 --- a/licenses/tailwind-merge@3.6.0/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Dany Castillo - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/tailwindcss@4.3.2/LICENSE b/licenses/tailwindcss@4.3.3/LICENSE similarity index 100% rename from licenses/tailwindcss@4.3.2/LICENSE rename to licenses/tailwindcss@4.3.3/LICENSE diff --git a/licenses/third-party-credits.json b/licenses/third-party-credits.json index 3481aba..9f4b971 100644 --- a/licenses/third-party-credits.json +++ b/licenses/third-party-credits.json @@ -1,46 +1,7 @@ { - "generatedAt": "2026-08-06T09:49:26.511Z", - "packageCount": 145, + "generatedAt": "2026-08-09T18:16:10.172Z", + "packageCount": 60, "packages": [ - { - "name": "@babel/runtime", - "version": "7.29.7", - "license": "MIT", - "homepage": "https://babel.dev/docs/en/next/babel-runtime", - "repository": "https://github.com/babel/babel.git", - "description": "babel's modular runtime helpers", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@babel_runtime@7.29.7", - "sourcePackageDir": "apps/web/node_modules/@babel/runtime" - }, - { - "name": "@base-ui/react", - "version": "1.6.0", - "license": "MIT", - "homepage": "https://base-ui.com", - "repository": "git+https://github.com/mui/base-ui.git", - "description": "Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@base-ui_react@1.6.0", - "sourcePackageDir": "apps/web/node_modules/@base-ui/react" - }, - { - "name": "@base-ui/utils", - "version": "0.3.2", - "license": "MIT", - "homepage": null, - "repository": "git+https://github.com/mui/base-ui.git", - "description": "A collection of React utility functions for Base UI.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@base-ui_utils@0.3.2", - "sourcePackageDir": "apps/web/node_modules/@base-ui/utils" - }, { "name": "@codemirror/autocomplete", "version": "6.20.3", @@ -69,15 +30,15 @@ }, { "name": "@codemirror/lang-markdown", - "version": "6.5.0", + "version": "6.5.2", "license": "MIT", "homepage": null, - "repository": "https://github.com/codemirror/lang-markdown.git", + "repository": "git+https://code.haverbeke.berlin/codemirror/lang-markdown.git", "description": "Markdown language support for the CodeMirror code editor", "files": [ "LICENSE" ], - "licenseFolder": "licenses/@codemirror_lang-markdown@6.5.0", + "licenseFolder": "licenses/@codemirror_lang-markdown@6.5.2", "sourcePackageDir": "packages/markdown/node_modules/@codemirror/lang-markdown" }, { @@ -95,7 +56,7 @@ }, { "name": "@codemirror/state", - "version": "6.7.0", + "version": "6.7.1", "license": "MIT", "homepage": null, "repository": "git+https://code.haverbeke.berlin/codemirror/state.git", @@ -103,12 +64,12 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@codemirror_state@6.7.0", + "licenseFolder": "licenses/@codemirror_state@6.7.1", "sourcePackageDir": "packages/markdown/node_modules/@codemirror/state" }, { "name": "@codemirror/view", - "version": "6.43.4", + "version": "6.43.8", "license": "MIT", "homepage": null, "repository": "git+https://code.haverbeke.berlin/codemirror/view.git", @@ -116,7 +77,7 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@codemirror_view@6.43.4", + "licenseFolder": "licenses/@codemirror_view@6.43.8", "sourcePackageDir": "packages/markdown/node_modules/@codemirror/view" }, { @@ -132,74 +93,9 @@ "licenseFolder": "licenses/@eslint_js@10.0.1", "sourcePackageDir": "apps/web/node_modules/@eslint/js" }, - { - "name": "@floating-ui/core", - "version": "1.7.5", - "license": "MIT", - "homepage": "https://floating-ui.com", - "repository": "https://github.com/floating-ui/floating-ui.git", - "description": "Positioning library for floating elements: tooltips, popovers, dropdowns, and more", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@floating-ui_core@1.7.5", - "sourcePackageDir": "apps/web/node_modules/@floating-ui/core" - }, - { - "name": "@floating-ui/dom", - "version": "1.7.6", - "license": "MIT", - "homepage": "https://floating-ui.com", - "repository": "https://github.com/floating-ui/floating-ui.git", - "description": "Floating UI for the web", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@floating-ui_dom@1.7.6", - "sourcePackageDir": "apps/web/node_modules/@floating-ui/dom" - }, - { - "name": "@floating-ui/react-dom", - "version": "2.1.8", - "license": "MIT", - "homepage": "https://floating-ui.com/docs/react-dom", - "repository": "https://github.com/floating-ui/floating-ui.git", - "description": "Floating UI for React DOM", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@floating-ui_react-dom@2.1.8", - "sourcePackageDir": "apps/web/node_modules/@floating-ui/react-dom" - }, - { - "name": "@floating-ui/utils", - "version": "0.2.11", - "license": "MIT", - "homepage": "https://floating-ui.com", - "repository": "https://github.com/floating-ui/floating-ui.git", - "description": "Utilities for Floating UI", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@floating-ui_utils@0.2.11", - "sourcePackageDir": "apps/web/node_modules/@floating-ui/utils" - }, - { - "name": "@fontsource-variable/inter", - "version": "5.2.8", - "license": "OFL-1.1", - "homepage": "https://fontsource.org/fonts/inter", - "repository": "git+https://github.com/fontsource/font-files.git", - "description": "Self-host the Inter font in a neatly bundled NPM package.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@fontsource-variable_inter@5.2.8", - "sourcePackageDir": "apps/web/node_modules/@fontsource-variable/inter" - }, { "name": "@fontsource-variable/public-sans", - "version": "5.2.7", + "version": "5.3.0", "license": "OFL-1.1", "homepage": "https://fontsource.org/fonts/public-sans", "repository": "git+https://github.com/fontsource/font-files.git", @@ -207,12 +103,12 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@fontsource-variable_public-sans@5.2.7", + "licenseFolder": "licenses/@fontsource-variable_public-sans@5.3.0", "sourcePackageDir": "apps/web/node_modules/@fontsource-variable/public-sans" }, { "name": "@livekit/components-react", - "version": "2.9.21", + "version": "2.9.23", "license": "Apache-2.0", "homepage": null, "repository": "https://github.com/livekit/components-js.git", @@ -220,7 +116,7 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@livekit_components-react@2.9.21", + "licenseFolder": "licenses/@livekit_components-react@2.9.23", "sourcePackageDir": "packages/call/node_modules/@livekit/components-react" }, { @@ -236,230 +132,9 @@ "licenseFolder": "licenses/@methanium_ui@0.0.22", "sourcePackageDir": "apps/tauri/node_modules/@methanium/ui" }, - { - "name": "@radix-ui/primitive", - "version": "1.1.4", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_primitive@1.1.4", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/primitive" - }, - { - "name": "@radix-ui/react-compose-refs", - "version": "1.1.3", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-compose-refs@1.1.3", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-compose-refs" - }, - { - "name": "@radix-ui/react-context", - "version": "1.1.4", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-context@1.1.4", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-context" - }, - { - "name": "@radix-ui/react-dialog", - "version": "1.1.18", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-dialog@1.1.18", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-dialog" - }, - { - "name": "@radix-ui/react-dismissable-layer", - "version": "1.1.14", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-dismissable-layer@1.1.14", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-dismissable-layer" - }, - { - "name": "@radix-ui/react-focus-guards", - "version": "1.1.4", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-focus-guards@1.1.4", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-focus-guards" - }, - { - "name": "@radix-ui/react-focus-scope", - "version": "1.1.11", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-focus-scope@1.1.11", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-focus-scope" - }, - { - "name": "@radix-ui/react-id", - "version": "1.1.2", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-id@1.1.2", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-id" - }, - { - "name": "@radix-ui/react-portal", - "version": "1.1.13", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-portal@1.1.13", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-portal" - }, - { - "name": "@radix-ui/react-presence", - "version": "1.1.6", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-presence@1.1.6", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-presence" - }, - { - "name": "@radix-ui/react-primitive", - "version": "2.1.7", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-primitive@2.1.7", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-primitive" - }, - { - "name": "@radix-ui/react-slot", - "version": "1.3.0", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-slot@1.3.0", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-slot" - }, - { - "name": "@radix-ui/react-use-callback-ref", - "version": "1.1.2", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-use-callback-ref@1.1.2", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-use-callback-ref" - }, - { - "name": "@radix-ui/react-use-controllable-state", - "version": "1.2.3", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-use-controllable-state@1.2.3", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-use-controllable-state" - }, - { - "name": "@radix-ui/react-use-effect-event", - "version": "0.0.5", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-use-effect-event@0.0.5", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-use-effect-event" - }, - { - "name": "@radix-ui/react-use-layout-effect", - "version": "1.1.2", - "license": "MIT", - "homepage": "https://radix-ui.com/primitives", - "repository": "git+https://github.com/radix-ui/primitives.git", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@radix-ui_react-use-layout-effect@1.1.2", - "sourcePackageDir": "apps/web/node_modules/@radix-ui/react-use-layout-effect" - }, - { - "name": "@reduxjs/toolkit", - "version": "2.12.0", - "license": "MIT", - "homepage": "https://redux-toolkit.js.org", - "repository": "git+https://github.com/reduxjs/redux-toolkit.git", - "description": "The official, opinionated, batteries-included toolset for efficient Redux development", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@reduxjs_toolkit@2.12.0", - "sourcePackageDir": "apps/web/node_modules/@reduxjs/toolkit" - }, { "name": "@tailwindcss/vite", - "version": "4.3.2", + "version": "4.3.3", "license": "MIT", "homepage": "https://tailwindcss.com", "repository": "https://github.com/tailwindlabs/tailwindcss.git", @@ -467,35 +142,9 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@tailwindcss_vite@4.3.2", + "licenseFolder": "licenses/@tailwindcss_vite@4.3.3", "sourcePackageDir": "apps/web/node_modules/@tailwindcss/vite" }, - { - "name": "@tanstack/devtools-event-client", - "version": "0.5.0", - "license": "MIT", - "homepage": "https://tanstack.com/devtools", - "repository": "git+https://github.com/TanStack/devtools.git", - "description": "TanStack Event Client is a lightweight event client for TanStack Devtools event bus.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@tanstack_devtools-event-client@0.5.0", - "sourcePackageDir": "apps/web/node_modules/@tanstack/devtools-event-client" - }, - { - "name": "@tanstack/history", - "version": "1.162.0", - "license": "MIT", - "homepage": "https://tanstack.com/router", - "repository": "git+https://github.com/TanStack/router.git", - "description": "Modern and scalable routing for React applications", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@tanstack_history@1.162.0", - "sourcePackageDir": "apps/web/node_modules/@tanstack/history" - }, { "name": "@tanstack/pacer", "version": "0.21.1", @@ -509,19 +158,6 @@ "licenseFolder": "licenses/@tanstack_pacer@0.21.1", "sourcePackageDir": "packages/chat/node_modules/@tanstack/pacer" }, - { - "name": "@tanstack/query-core", - "version": "5.101.2", - "license": "MIT", - "homepage": "https://tanstack.com/query", - "repository": "git+https://github.com/TanStack/query.git", - "description": "The framework agnostic core that powers TanStack Query", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@tanstack_query-core@5.101.2", - "sourcePackageDir": "apps/web/node_modules/@tanstack/query-core" - }, { "name": "@tanstack/react-hotkeys", "version": "0.10.0", @@ -537,7 +173,7 @@ }, { "name": "@tanstack/react-query", - "version": "5.101.2", + "version": "5.101.4", "license": "MIT", "homepage": "https://tanstack.com/query", "repository": "git+https://github.com/TanStack/query.git", @@ -545,12 +181,12 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@tanstack_react-query@5.101.2", + "licenseFolder": "licenses/@tanstack_react-query@5.101.4", "sourcePackageDir": "packages/chat/node_modules/@tanstack/react-query" }, { "name": "@tanstack/react-router", - "version": "1.170.17", + "version": "1.170.23", "license": "MIT", "homepage": "https://tanstack.com/router", "repository": "git+https://github.com/TanStack/router.git", @@ -558,25 +194,12 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@tanstack_react-router@1.170.17", + "licenseFolder": "licenses/@tanstack_react-router@1.170.23", "sourcePackageDir": "apps/web/node_modules/@tanstack/react-router" }, - { - "name": "@tanstack/react-store", - "version": "0.11.0", - "license": "MIT", - "homepage": "https://tanstack.com/store", - "repository": "https://github.com/TanStack/store.git", - "description": "Framework agnostic type-safe store w/ reactive framework adapters", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@tanstack_react-store@0.11.0", - "sourcePackageDir": "apps/web/node_modules/@tanstack/react-store" - }, { "name": "@tanstack/react-virtual", - "version": "3.14.5", + "version": "3.14.9", "license": "MIT", "homepage": "https://tanstack.com/virtual", "repository": "git+https://github.com/TanStack/virtual.git", @@ -584,48 +207,9 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@tanstack_react-virtual@3.14.5", + "licenseFolder": "licenses/@tanstack_react-virtual@3.14.9", "sourcePackageDir": "apps/web/node_modules/@tanstack/react-virtual" }, - { - "name": "@tanstack/router-core", - "version": "1.171.14", - "license": "MIT", - "homepage": "https://tanstack.com/router", - "repository": "git+https://github.com/TanStack/router.git", - "description": "Modern and scalable routing for React applications", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@tanstack_router-core@1.171.14", - "sourcePackageDir": "apps/web/node_modules/@tanstack/router-core" - }, - { - "name": "@tanstack/store", - "version": "0.11.0", - "license": "MIT", - "homepage": "https://tanstack.com/store", - "repository": "git+https://github.com/TanStack/store.git", - "description": "Framework agnostic type-safe store w/ reactive framework adapters", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@tanstack_store@0.11.0", - "sourcePackageDir": "apps/web/node_modules/@tanstack/store" - }, - { - "name": "@tanstack/virtual-core", - "version": "3.17.3", - "license": "MIT", - "homepage": "https://tanstack.com/virtual", - "repository": "git+https://github.com/TanStack/virtual.git", - "description": "Headless UI for virtualizing scrollable elements in TS/JS + Frameworks", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@tanstack_virtual-core@3.17.3", - "sourcePackageDir": "apps/web/node_modules/@tanstack/virtual-core" - }, { "name": "@tauri-apps/api", "version": "2.11.1", @@ -680,19 +264,6 @@ "licenseFolder": "licenses/@tauri-apps_plugin-deep-link@2.4.9", "sourcePackageDir": "apps/tauri/node_modules/@tauri-apps/plugin-deep-link" }, - { - "name": "@tauri-apps/plugin-log", - "version": "2.8.0", - "license": "MIT OR Apache-2.0", - "homepage": null, - "repository": "https://github.com/tauri-apps/plugins-workspace", - "description": "Configurable logging for your Tauri app.", - "files": [ - "LICENSE.spdx" - ], - "licenseFolder": "licenses/@tauri-apps_plugin-log@2.8.0", - "sourcePackageDir": "apps/tauri/node_modules/@tauri-apps/plugin-log" - }, { "name": "@tauri-apps/plugin-notification", "version": "2.3.3", @@ -704,7 +275,7 @@ "LICENSE.spdx" ], "licenseFolder": "licenses/@tauri-apps_plugin-notification@2.3.3", - "sourcePackageDir": "apps/tauri/node_modules/@tauri-apps/plugin-notification" + "sourcePackageDir": "packages/notifications/node_modules/@tauri-apps/plugin-notification" }, { "name": "@twemoji/api", @@ -721,7 +292,7 @@ }, { "name": "@types/node", - "version": "25.9.4", + "version": "26.2.0", "license": "MIT", "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node", "repository": "https://github.com/DefinitelyTyped/DefinitelyTyped.git", @@ -729,7 +300,7 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@types_node@25.9.4", + "licenseFolder": "licenses/@types_node@26.2.0", "sourcePackageDir": "apps/electron/node_modules/@types/node" }, { @@ -747,7 +318,7 @@ }, { "name": "@types/react", - "version": "19.2.17", + "version": "19.2.18", "license": "MIT", "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react", "repository": "https://github.com/DefinitelyTyped/DefinitelyTyped.git", @@ -755,12 +326,12 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@types_react@19.2.17", + "licenseFolder": "licenses/@types_react@19.2.18", "sourcePackageDir": "apps/web/node_modules/@types/react" }, { "name": "@types/react-dom", - "version": "19.2.3", + "version": "19.2.4", "license": "MIT", "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-dom", "repository": "https://github.com/DefinitelyTyped/DefinitelyTyped.git", @@ -768,12 +339,12 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@types_react-dom@19.2.3", + "licenseFolder": "licenses/@types_react-dom@19.2.4", "sourcePackageDir": "apps/web/node_modules/@types/react-dom" }, { "name": "@typescript-eslint/parser", - "version": "8.62.1", + "version": "8.66.0", "license": "MIT", "homepage": "https://typescript-eslint.io/packages/parser", "repository": "https://github.com/typescript-eslint/typescript-eslint.git", @@ -781,12 +352,12 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@typescript-eslint_parser@8.62.1", + "licenseFolder": "licenses/@typescript-eslint_parser@8.66.0", "sourcePackageDir": "node_modules/@typescript-eslint/parser" }, { "name": "@vitejs/plugin-react", - "version": "6.0.3", + "version": "6.0.5", "license": "MIT", "homepage": "https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#readme", "repository": "git+https://github.com/vitejs/vite-plugin-react.git", @@ -794,230 +365,9 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@vitejs_plugin-react@6.0.3", + "licenseFolder": "licenses/@vitejs_plugin-react@6.0.5", "sourcePackageDir": "apps/web/node_modules/@vitejs/plugin-react" }, - { - "name": "aria-hidden", - "version": "1.2.6", - "license": "MIT", - "homepage": "https://github.com/theKashey/aria-hidden#readme", - "repository": "git+https://github.com/theKashey/aria-hidden.git", - "description": "Cast aria-hidden to everything, except...", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/aria-hidden@1.2.6", - "sourcePackageDir": "apps/web/node_modules/aria-hidden" - }, - { - "name": "class-variance-authority", - "version": "0.7.1", - "license": "Apache-2.0", - "homepage": "https://github.com/joe-bell/cva#readme", - "repository": "https://github.com/joe-bell/cva.git", - "description": "Class Variance Authority 🧬", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/class-variance-authority@0.7.1", - "sourcePackageDir": "apps/web/node_modules/class-variance-authority" - }, - { - "name": "clsx", - "version": "2.1.1", - "license": "MIT", - "homepage": null, - "repository": "lukeed/clsx", - "description": "A tiny (239B) utility for constructing className strings conditionally.", - "files": [ - "license" - ], - "licenseFolder": "licenses/clsx@2.1.1", - "sourcePackageDir": "apps/web/node_modules/clsx" - }, - { - "name": "cmdk", - "version": "1.1.1", - "license": "MIT", - "homepage": "https://github.com/pacocoursey/cmdk#readme", - "repository": "git+https://github.com/pacocoursey/cmdk.git", - "description": null, - "files": [ - "LICENSE.md" - ], - "licenseFolder": "licenses/cmdk@1.1.1", - "sourcePackageDir": "apps/web/node_modules/cmdk" - }, - { - "name": "cookie-es", - "version": "3.1.1", - "license": "MIT", - "homepage": null, - "repository": "unjs/cookie-es", - "description": null, - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/cookie-es@3.1.1", - "sourcePackageDir": "apps/web/node_modules/cookie-es" - }, - { - "name": "d3-array", - "version": "3.2.4", - "license": "ISC", - "homepage": "https://d3js.org/d3-array/", - "repository": "https://github.com/d3/d3-array.git", - "description": "Array manipulation, ordering, searching, summarizing, etc.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/d3-array@3.2.4", - "sourcePackageDir": "apps/web/node_modules/d3-array" - }, - { - "name": "d3-color", - "version": "3.1.0", - "license": "ISC", - "homepage": "https://d3js.org/d3-color/", - "repository": "https://github.com/d3/d3-color.git", - "description": "Color spaces! RGB, HSL, Cubehelix, Lab and HCL (Lch).", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/d3-color@3.1.0", - "sourcePackageDir": "apps/web/node_modules/d3-color" - }, - { - "name": "d3-ease", - "version": "3.0.1", - "license": "BSD-3-Clause", - "homepage": "https://d3js.org/d3-ease/", - "repository": "https://github.com/d3/d3-ease.git", - "description": "Easing functions for smooth animation.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/d3-ease@3.0.1", - "sourcePackageDir": "apps/web/node_modules/d3-ease" - }, - { - "name": "d3-format", - "version": "3.1.2", - "license": "ISC", - "homepage": "https://d3js.org/d3-format/", - "repository": "https://github.com/d3/d3-format.git", - "description": "Format numbers for human consumption.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/d3-format@3.1.2", - "sourcePackageDir": "apps/web/node_modules/d3-format" - }, - { - "name": "d3-interpolate", - "version": "3.0.1", - "license": "ISC", - "homepage": "https://d3js.org/d3-interpolate/", - "repository": "https://github.com/d3/d3-interpolate.git", - "description": "Interpolate numbers, colors, strings, arrays, objects, whatever!", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/d3-interpolate@3.0.1", - "sourcePackageDir": "apps/web/node_modules/d3-interpolate" - }, - { - "name": "d3-path", - "version": "3.1.0", - "license": "ISC", - "homepage": "https://d3js.org/d3-path/", - "repository": "https://github.com/d3/d3-path.git", - "description": "Serialize Canvas path commands to SVG.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/d3-path@3.1.0", - "sourcePackageDir": "apps/web/node_modules/d3-path" - }, - { - "name": "d3-scale", - "version": "4.0.2", - "license": "ISC", - "homepage": "https://d3js.org/d3-scale/", - "repository": "https://github.com/d3/d3-scale.git", - "description": "Encodings that map abstract data to visual representation.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/d3-scale@4.0.2", - "sourcePackageDir": "apps/web/node_modules/d3-scale" - }, - { - "name": "d3-shape", - "version": "3.2.0", - "license": "ISC", - "homepage": "https://d3js.org/d3-shape/", - "repository": "https://github.com/d3/d3-shape.git", - "description": "Graphical primitives for visualization, such as lines and areas.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/d3-shape@3.2.0", - "sourcePackageDir": "apps/web/node_modules/d3-shape" - }, - { - "name": "d3-time", - "version": "3.1.0", - "license": "ISC", - "homepage": "https://d3js.org/d3-time/", - "repository": "https://github.com/d3/d3-time.git", - "description": "A calculator for humanity’s peculiar conventions of time.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/d3-time@3.1.0", - "sourcePackageDir": "apps/web/node_modules/d3-time" - }, - { - "name": "d3-time-format", - "version": "4.1.0", - "license": "ISC", - "homepage": "https://d3js.org/d3-time-format/", - "repository": "https://github.com/d3/d3-time-format.git", - "description": "A JavaScript time formatter and parser inspired by strftime and strptime.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/d3-time-format@4.1.0", - "sourcePackageDir": "apps/web/node_modules/d3-time-format" - }, - { - "name": "d3-timer", - "version": "3.0.1", - "license": "ISC", - "homepage": "https://d3js.org/d3-timer/", - "repository": "https://github.com/d3/d3-timer.git", - "description": "An efficient queue capable of managing thousands of concurrent animations.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/d3-timer@3.0.1", - "sourcePackageDir": "apps/web/node_modules/d3-timer" - }, - { - "name": "date-fns", - "version": "4.4.0", - "license": "MIT", - "homepage": null, - "repository": "https://github.com/date-fns/date-fns", - "description": "Modern JavaScript date utility library", - "files": [ - "LICENSE.md" - ], - "licenseFolder": "licenses/date-fns@4.4.0", - "sourcePackageDir": "apps/web/node_modules/date-fns" - }, { "name": "decimal.js-light", "version": "2.5.1", @@ -1045,35 +395,9 @@ "licenseFolder": "licenses/deepfilternet3-noise-filter@1.3.0", "sourcePackageDir": "packages/call/node_modules/deepfilternet3-noise-filter" }, - { - "name": "detect-node-es", - "version": "1.1.0", - "license": "MIT", - "homepage": "https://github.com/thekashey/detect-node", - "repository": "https://github.com/thekashey/detect-node", - "description": "Detect Node.JS (as opposite to browser environment). ESM modification", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/detect-node-es@1.1.0", - "sourcePackageDir": "apps/web/node_modules/detect-node-es" - }, - { - "name": "dijkstrajs", - "version": "1.0.3", - "license": "MIT", - "homepage": "https://github.com/tcort/dijkstrajs", - "repository": "git://github.com/tcort/dijkstrajs", - "description": "A simple JavaScript implementation of Dijkstra's single-source shortest-paths algorithm.", - "files": [ - "LICENSE.md" - ], - "licenseFolder": "licenses/dijkstrajs@1.0.3", - "sourcePackageDir": "apps/web/node_modules/dijkstrajs" - }, { "name": "electron", - "version": "39.8.10", + "version": "43.3.0", "license": "MIT", "homepage": null, "repository": "https://github.com/electron/electron", @@ -1081,7 +405,7 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/electron@39.8.10", + "licenseFolder": "licenses/electron@43.3.0", "sourcePackageDir": "apps/electron/node_modules/electron" }, { @@ -1097,39 +421,6 @@ "licenseFolder": "licenses/electron-builder@26.15.3", "sourcePackageDir": "apps/electron/node_modules/electron-builder" }, - { - "name": "embla-carousel", - "version": "8.6.0", - "license": "MIT", - "homepage": "https://www.embla-carousel.com", - "repository": "git+https://github.com/davidjerleke/embla-carousel", - "description": "A lightweight carousel library with fluid motion and great swipe precision", - "files": [], - "licenseFolder": "licenses/embla-carousel@8.6.0", - "sourcePackageDir": "apps/web/node_modules/embla-carousel" - }, - { - "name": "embla-carousel-react", - "version": "8.6.0", - "license": "MIT", - "homepage": "https://www.embla-carousel.com", - "repository": "git+https://github.com/davidjerleke/embla-carousel", - "description": "A lightweight carousel library with fluid motion and great swipe precision", - "files": [], - "licenseFolder": "licenses/embla-carousel-react@8.6.0", - "sourcePackageDir": "apps/web/node_modules/embla-carousel-react" - }, - { - "name": "embla-carousel-reactive-utils", - "version": "8.6.0", - "license": "MIT", - "homepage": "https://www.embla-carousel.com", - "repository": "git+https://github.com/davidjerleke/embla-carousel", - "description": "Reactive utilities for Embla Carousel", - "files": [], - "licenseFolder": "licenses/embla-carousel-reactive-utils@8.6.0", - "sourcePackageDir": "apps/web/node_modules/embla-carousel-reactive-utils" - }, { "name": "emojibase-data", "version": "17.0.0", @@ -1143,19 +434,6 @@ "licenseFolder": "licenses/emojibase-data@17.0.0", "sourcePackageDir": "packages/markdown/node_modules/emojibase-data" }, - { - "name": "es-toolkit", - "version": "1.49.0", - "license": "MIT", - "homepage": "https://es-toolkit.dev", - "repository": "https://github.com/toss/es-toolkit.git", - "description": "A state-of-the-art, high-performance JavaScript utility library with a small bundle size and strong type annotations.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/es-toolkit@1.49.0", - "sourcePackageDir": "apps/web/node_modules/es-toolkit" - }, { "name": "esbuild", "version": "0.28.1", @@ -1171,7 +449,7 @@ }, { "name": "eslint", - "version": "10.6.0", + "version": "10.8.1", "license": "MIT", "homepage": "https://eslint.org", "repository": "eslint/eslint", @@ -1179,7 +457,7 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/eslint@10.6.0", + "licenseFolder": "licenses/eslint@10.8.1", "sourcePackageDir": "apps/web/node_modules/eslint" }, { @@ -1210,31 +488,18 @@ }, { "name": "fallow", - "version": "2.104.0", + "version": "3.14.0", "license": "MIT", "homepage": "https://docs.fallow.tools", "repository": "git+https://github.com/fallow-rs/fallow.git", - "description": "Deterministic codebase intelligence for TypeScript and JavaScript. Quality, risk, architecture, dependencies, duplication, and safe cleanup evidence for humans, CI, and agents. Optional runtime intelligence layer (Fallow Runtime) adds production execution evidence. Rust-native, sub-second, zero-config framework support.", + "description": "Codebase intelligence for TypeScript and JavaScript. Free static analysis of code and styles, optional paid runtime intelligence (Fallow Runtime). Quality, risk, architecture, dependencies, duplication, and design-system drift for humans, CI, and the agents writing your code. Zero-config framework support.", "files": [], - "licenseFolder": "licenses/fallow@2.104.0", + "licenseFolder": "licenses/fallow@3.14.0", "sourcePackageDir": "node_modules/fallow" }, - { - "name": "get-nonce", - "version": "1.0.1", - "license": "MIT", - "homepage": "https://github.com/theKashey/get-nonce", - "repository": "git@github.com:theKashey/get-nonce.git", - "description": "returns nonce", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/get-nonce@1.0.1", - "sourcePackageDir": "apps/web/node_modules/get-nonce" - }, { "name": "globals", - "version": "17.7.0", + "version": "17.9.0", "license": "MIT", "homepage": null, "repository": "sindresorhus/globals", @@ -1242,62 +507,12 @@ "files": [ "license" ], - "licenseFolder": "licenses/globals@17.7.0", + "licenseFolder": "licenses/globals@17.9.0", "sourcePackageDir": "apps/web/node_modules/globals" }, - { - "name": "immer", - "version": "10.2.0", - "license": "MIT", - "homepage": "https://github.com/immerjs/immer#readme", - "repository": "https://github.com/immerjs/immer.git", - "description": "Create your next immutable state by mutating the current one", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/immer@10.2.0", - "sourcePackageDir": "apps/web/node_modules/immer" - }, - { - "name": "input-otp", - "version": "1.4.2", - "license": "MIT", - "homepage": "https://input-otp.rodz.dev/", - "repository": "git+https://github.com/guilhermerodz/input-otp.git", - "description": "One-time password input component for React.", - "files": [], - "licenseFolder": "licenses/input-otp@1.4.2", - "sourcePackageDir": "apps/web/node_modules/input-otp" - }, - { - "name": "internmap", - "version": "2.0.3", - "license": "ISC", - "homepage": "https://github.com/mbostock/internmap/", - "repository": "https://github.com/mbostock/internmap.git", - "description": "Map and Set with automatic key interning", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/internmap@2.0.3", - "sourcePackageDir": "apps/web/node_modules/internmap" - }, - { - "name": "jsonc-parser", - "version": "3.3.1", - "license": "MIT", - "homepage": null, - "repository": "https://github.com/microsoft/node-jsonc-parser", - "description": "Scanner and parser for JSON with comments.", - "files": [ - "LICENSE.md" - ], - "licenseFolder": "licenses/jsonc-parser@3.3.1", - "sourcePackageDir": "node_modules/jsonc-parser" - }, { "name": "livekit-client", - "version": "2.20.0", + "version": "2.21.0", "license": "Apache-2.0", "homepage": null, "repository": "git@github.com:livekit/client-sdk-js.git", @@ -1305,12 +520,12 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/livekit-client@2.20.0", + "licenseFolder": "licenses/livekit-client@2.21.0", "sourcePackageDir": "packages/call/node_modules/livekit-client" }, { "name": "lucide-react", - "version": "1.23.0", + "version": "1.30.0", "license": "ISC", "homepage": "https://lucide.dev", "repository": "https://github.com/lucide-icons/lucide.git", @@ -1318,12 +533,12 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/lucide-react@1.23.0", + "licenseFolder": "licenses/lucide-react@1.30.0", "sourcePackageDir": "apps/web/node_modules/lucide-react" }, { "name": "motion", - "version": "12.42.2", + "version": "13.0.0", "license": "MIT", "homepage": null, "repository": "https://github.com/motiondivision/motion", @@ -1331,7 +546,7 @@ "files": [ "LICENSE.md" ], - "licenseFolder": "licenses/motion@12.42.2", + "licenseFolder": "licenses/motion@13.0.0", "sourcePackageDir": "packages/chat/node_modules/motion" }, { @@ -1345,35 +560,9 @@ "licenseFolder": "licenses/mtp@0.2.0", "sourcePackageDir": "packages/mtp/node_modules/mtp" }, - { - "name": "next-themes", - "version": "0.4.6", - "license": "MIT", - "homepage": null, - "repository": "https://github.com/pacocoursey/next-themes.git", - "description": null, - "files": [ - "license.md" - ], - "licenseFolder": "licenses/next-themes@0.4.6", - "sourcePackageDir": "apps/web/node_modules/next-themes" - }, - { - "name": "pngjs", - "version": "5.0.0", - "license": "MIT", - "homepage": "https://github.com/lukeapage/pngjs", - "repository": "git://github.com/lukeapage/pngjs.git", - "description": "PNG encoder/decoder in pure JS, supporting any bit size & interlace, async & sync with full test suite.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/pngjs@5.0.0", - "sourcePackageDir": "apps/web/node_modules/pngjs" - }, { "name": "prettier", - "version": "3.9.4", + "version": "3.9.6", "license": "MIT", "homepage": "https://prettier.io", "repository": "prettier/prettier", @@ -1381,72 +570,46 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/prettier@3.9.4", + "licenseFolder": "licenses/prettier@3.9.6", "sourcePackageDir": "node_modules/prettier" }, - { - "name": "qrcode", - "version": "1.5.4", - "license": "MIT", - "homepage": "http://github.com/soldair/node-qrcode", - "repository": "git://github.com/soldair/node-qrcode.git", - "description": "QRCode / 2d Barcode api with both server side and client side support using canvas", - "files": [ - "license" - ], - "licenseFolder": "licenses/qrcode@1.5.4", - "sourcePackageDir": "apps/web/node_modules/qrcode" - }, { "name": "react", - "version": "19.2.7", + "version": "19.2.8", "license": "MIT", "homepage": "https://react.dev/", - "repository": "https://github.com/facebook/react.git", + "repository": "https://github.com/react/react.git", "description": "React is a JavaScript library for building user interfaces.", "files": [ "LICENSE" ], - "licenseFolder": "licenses/react@19.2.7", + "licenseFolder": "licenses/react@19.2.8", "sourcePackageDir": "apps/tauri/node_modules/react" }, - { - "name": "react-day-picker", - "version": "10.0.1", - "license": "MIT", - "homepage": "https://daypicker.dev", - "repository": "git+https://github.com/gpbl/react-day-picker.git", - "description": "Customizable Date Picker for React", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/react-day-picker@10.0.1", - "sourcePackageDir": "apps/web/node_modules/react-day-picker" - }, { "name": "react-dom", - "version": "19.2.7", + "version": "19.2.8", "license": "MIT", "homepage": "https://react.dev/", - "repository": "https://github.com/facebook/react.git", + "repository": "https://github.com/react/react.git", "description": "React package for working with the DOM.", "files": [ "LICENSE" ], - "licenseFolder": "licenses/react-dom@19.2.7", + "licenseFolder": "licenses/react-dom@19.2.8", "sourcePackageDir": "apps/tauri/node_modules/react-dom" }, { "name": "react-is", - "version": "19.2.7", + "version": "19.2.8", "license": "MIT", "homepage": "https://react.dev/", - "repository": "https://github.com/facebook/react.git", + "repository": "https://github.com/react/react.git", "description": "Brand checking of React Elements.", "files": [ "LICENSE" ], - "licenseFolder": "licenses/react-is@19.2.7", + "licenseFolder": "licenses/react-is@19.2.8", "sourcePackageDir": "apps/web/node_modules/react-is" }, { @@ -1462,56 +625,6 @@ "licenseFolder": "licenses/react-redux@9.3.0", "sourcePackageDir": "apps/web/node_modules/react-redux" }, - { - "name": "react-remove-scroll", - "version": "2.7.2", - "license": "MIT", - "homepage": null, - "repository": "https://github.com/theKashey/react-remove-scroll", - "description": "Disables scroll outside of `children` node.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/react-remove-scroll@2.7.2", - "sourcePackageDir": "apps/web/node_modules/react-remove-scroll" - }, - { - "name": "react-remove-scroll-bar", - "version": "2.3.8", - "license": "MIT", - "homepage": null, - "repository": "https://github.com/theKashey/react-remove-scroll-bar", - "description": "Removes body scroll without content _shake_", - "files": [], - "licenseFolder": "licenses/react-remove-scroll-bar@2.3.8", - "sourcePackageDir": "apps/web/node_modules/react-remove-scroll-bar" - }, - { - "name": "react-resizable-panels", - "version": "4.12.0", - "license": "MIT", - "homepage": "https://react-resizable-panels.vercel.app/", - "repository": "https://github.com/bvaughn/react-resizable-panels.git", - "description": null, - "files": [ - "LICENSE.md" - ], - "licenseFolder": "licenses/react-resizable-panels@4.12.0", - "sourcePackageDir": "apps/web/node_modules/react-resizable-panels" - }, - { - "name": "react-style-singleton", - "version": "2.2.3", - "license": "MIT", - "homepage": "https://github.com/theKashey/react-style-singleton#readme", - "repository": "https://github.com/theKashey/react-style-singleton", - "description": "Just create a single stylesheet...", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/react-style-singleton@2.2.3", - "sourcePackageDir": "apps/web/node_modules/react-style-singleton" - }, { "name": "recharts", "version": "3.10.1", @@ -1523,98 +636,7 @@ "LICENSE" ], "licenseFolder": "licenses/recharts@3.10.1", - "sourcePackageDir": "apps/web/node_modules/recharts" - }, - { - "name": "redux", - "version": "5.0.1", - "license": "MIT", - "homepage": "http://redux.js.org", - "repository": "github:reduxjs/redux", - "description": "Predictable state container for JavaScript apps", - "files": [ - "LICENSE.md" - ], - "licenseFolder": "licenses/redux@5.0.1", - "sourcePackageDir": "apps/web/node_modules/redux" - }, - { - "name": "redux-thunk", - "version": "3.1.0", - "license": "MIT", - "homepage": "https://github.com/reduxjs/redux-thunk", - "repository": "github:reduxjs/redux-thunk", - "description": "Thunk middleware for Redux.", - "files": [ - "LICENSE.md" - ], - "licenseFolder": "licenses/redux-thunk@3.1.0", - "sourcePackageDir": "apps/web/node_modules/redux-thunk" - }, - { - "name": "reselect", - "version": "5.1.1", - "license": "MIT", - "homepage": null, - "repository": "https://github.com/reduxjs/reselect.git", - "description": "Selectors for Redux.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/reselect@5.1.1", - "sourcePackageDir": "apps/web/node_modules/reselect" - }, - { - "name": "scheduler", - "version": "0.27.0", - "license": "MIT", - "homepage": "https://react.dev/", - "repository": "https://github.com/facebook/react.git", - "description": "Cooperative scheduler for the browser environment.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/scheduler@0.27.0", - "sourcePackageDir": "apps/web/node_modules/scheduler" - }, - { - "name": "seroval", - "version": "1.5.4", - "license": "MIT", - "homepage": "https://github.com/lxsmnsyc/seroval/tree/main/packages/seroval", - "repository": "https://github.com/lxsmnsyc/seroval.git", - "description": "Stringify JS values", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/seroval@1.5.4", - "sourcePackageDir": "apps/web/node_modules/seroval" - }, - { - "name": "seroval-plugins", - "version": "1.5.4", - "license": "MIT", - "homepage": "https://github.com/lxsmnsyc/seroval/tree/main/packages/plugins", - "repository": "https://github.com/lxsmnsyc/seroval.git", - "description": "Stringify JS values", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/seroval-plugins@1.5.4", - "sourcePackageDir": "apps/web/node_modules/seroval-plugins" - }, - { - "name": "shadcn", - "version": "4.12.0", - "license": "MIT", - "homepage": null, - "repository": "https://github.com/shadcn-ui/ui.git", - "description": "Add components to your apps.", - "files": [ - "LICENSE.md" - ], - "licenseFolder": "licenses/shadcn@4.12.0", - "sourcePackageDir": "apps/web/node_modules/shadcn" + "sourcePackageDir": "packages/call/node_modules/recharts" }, { "name": "sonner", @@ -1627,20 +649,7 @@ "LICENSE.md" ], "licenseFolder": "licenses/sonner@2.0.7", - "sourcePackageDir": "apps/web/node_modules/sonner" - }, - { - "name": "tailwind-merge", - "version": "3.6.0", - "license": "MIT", - "homepage": "https://github.com/dcastil/tailwind-merge", - "repository": "https://github.com/dcastil/tailwind-merge.git", - "description": "Merge Tailwind CSS classes without style conflicts", - "files": [ - "LICENSE.md" - ], - "licenseFolder": "licenses/tailwind-merge@3.6.0", - "sourcePackageDir": "apps/web/node_modules/tailwind-merge" + "sourcePackageDir": "packages/notifications/node_modules/sonner" }, { "name": "tailwind-scrollbar-hide", @@ -1657,7 +666,7 @@ }, { "name": "tailwindcss", - "version": "4.3.2", + "version": "4.3.3", "license": "MIT", "homepage": "https://tailwindcss.com", "repository": "https://github.com/tailwindlabs/tailwindcss.git", @@ -1665,35 +674,9 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/tailwindcss@4.3.2", + "licenseFolder": "licenses/tailwindcss@4.3.3", "sourcePackageDir": "apps/web/node_modules/tailwindcss" }, - { - "name": "tiny-invariant", - "version": "1.3.3", - "license": "MIT", - "homepage": null, - "repository": "https://github.com/alexreardon/tiny-invariant.git", - "description": "A tiny invariant function", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/tiny-invariant@1.3.3", - "sourcePackageDir": "apps/web/node_modules/tiny-invariant" - }, - { - "name": "tslib", - "version": "2.8.1", - "license": "0BSD", - "homepage": "https://www.typescriptlang.org/", - "repository": "https://github.com/Microsoft/tslib.git", - "description": "Runtime library for TypeScript helper functions", - "files": [ - "LICENSE.txt" - ], - "licenseFolder": "licenses/tslib@2.8.1", - "sourcePackageDir": "apps/web/node_modules/tslib" - }, { "name": "tw-animate-css", "version": "1.4.0", @@ -1722,7 +705,7 @@ }, { "name": "typescript-eslint", - "version": "8.62.1", + "version": "8.66.0", "license": "MIT", "homepage": "https://typescript-eslint.io/packages/typescript-eslint", "repository": "https://github.com/typescript-eslint/typescript-eslint.git", @@ -1730,35 +713,9 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/typescript-eslint@8.62.1", + "licenseFolder": "licenses/typescript-eslint@8.66.0", "sourcePackageDir": "apps/web/node_modules/typescript-eslint" }, - { - "name": "use-callback-ref", - "version": "1.3.3", - "license": "MIT", - "homepage": null, - "repository": "https://github.com/theKashey/use-callback-ref/", - "description": "The same useRef, but with callback", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/use-callback-ref@1.3.3", - "sourcePackageDir": "apps/web/node_modules/use-callback-ref" - }, - { - "name": "use-sidecar", - "version": "1.1.3", - "license": "MIT", - "homepage": "https://github.com/theKashey/use-sidecar", - "repository": "https://github.com/theKashey/use-sidecar", - "description": "Sidecar code splitting utils", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/use-sidecar@1.1.3", - "sourcePackageDir": "apps/web/node_modules/use-sidecar" - }, { "name": "use-sync-external-store", "version": "1.6.0", @@ -1772,33 +729,9 @@ "licenseFolder": "licenses/use-sync-external-store@1.6.0", "sourcePackageDir": "apps/web/node_modules/use-sync-external-store" }, - { - "name": "vaul", - "version": "1.1.2", - "license": "MIT", - "homepage": "https://vaul.emilkowal.ski/", - "repository": "https://github.com/emilkowalski/vaul.git", - "description": "Drawer component for React.", - "files": [ - "LICENSE.md" - ], - "licenseFolder": "licenses/vaul@1.1.2", - "sourcePackageDir": "apps/web/node_modules/vaul" - }, - { - "name": "victory-vendor", - "version": "37.3.6", - "license": "MIT AND ISC", - "homepage": "https://commerce.nearform.com/open-source/victory", - "repository": "https://github.com/FormidableLabs/victory", - "description": "Vendored dependencies for Victory", - "files": [], - "licenseFolder": "licenses/victory-vendor@37.3.6", - "sourcePackageDir": "apps/web/node_modules/victory-vendor" - }, { "name": "vite", - "version": "8.1.3", + "version": "8.2.1", "license": "MIT", "homepage": "https://vite.dev", "repository": "git+https://github.com/vitejs/vite.git", @@ -1806,12 +739,12 @@ "files": [ "LICENSE.md" ], - "licenseFolder": "licenses/vite@8.1.3", + "licenseFolder": "licenses/vite@8.2.1", "sourcePackageDir": "apps/web/node_modules/vite" }, { "name": "vitest", - "version": "4.1.9", + "version": "4.1.10", "license": "MIT", "homepage": "https://vitest.dev", "repository": "git+https://github.com/vitest-dev/vitest.git", @@ -1819,35 +752,9 @@ "files": [ "LICENSE.md" ], - "licenseFolder": "licenses/vitest@4.1.9", + "licenseFolder": "licenses/vitest@4.1.10", "sourcePackageDir": "node_modules/vitest" }, - { - "name": "yaml", - "version": "2.9.0", - "license": "ISC", - "homepage": "https://eemeli.org/yaml/", - "repository": "github:eemeli/yaml", - "description": "JavaScript parser and stringifier for YAML", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/yaml@2.9.0", - "sourcePackageDir": "node_modules/yaml" - }, - { - "name": "yargs", - "version": "15.4.1", - "license": "MIT", - "homepage": "https://yargs.js.org/", - "repository": "https://github.com/yargs/yargs.git", - "description": "yargs the modern, pirate-themed, successor to optimist.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/yargs@15.4.1", - "sourcePackageDir": "apps/web/node_modules/yargs" - }, { "name": "zod", "version": "4.4.3", diff --git a/licenses/tiny-invariant@1.3.3/LICENSE b/licenses/tiny-invariant@1.3.3/LICENSE deleted file mode 100644 index f3dcb58..0000000 --- a/licenses/tiny-invariant@1.3.3/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 Alexander Reardon - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/licenses/tslib@2.8.1/LICENSE.txt b/licenses/tslib@2.8.1/LICENSE.txt deleted file mode 100644 index bfe6430..0000000 --- a/licenses/tslib@2.8.1/LICENSE.txt +++ /dev/null @@ -1,12 +0,0 @@ -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/licenses/typescript-eslint@8.62.1/LICENSE b/licenses/typescript-eslint@8.66.0/LICENSE similarity index 100% rename from licenses/typescript-eslint@8.62.1/LICENSE rename to licenses/typescript-eslint@8.66.0/LICENSE diff --git a/licenses/use-callback-ref@1.3.3/LICENSE b/licenses/use-callback-ref@1.3.3/LICENSE deleted file mode 100644 index a194c88..0000000 --- a/licenses/use-callback-ref@1.3.3/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Anton Korzunov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/use-sidecar@1.1.3/LICENSE b/licenses/use-sidecar@1.1.3/LICENSE deleted file mode 100644 index a194c88..0000000 --- a/licenses/use-sidecar@1.1.3/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Anton Korzunov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/vaul@1.1.2/LICENSE.md b/licenses/vaul@1.1.2/LICENSE.md deleted file mode 100644 index 03986c1..0000000 --- a/licenses/vaul@1.1.2/LICENSE.md +++ /dev/null @@ -1,9 +0,0 @@ -MIT License - -Copyright (c) 2023 Emil Kowalski - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/vite@8.1.3/LICENSE.md b/licenses/vite@8.2.1/LICENSE.md similarity index 98% rename from licenses/vite@8.1.3/LICENSE.md rename to licenses/vite@8.2.1/LICENSE.md index ccf4c21..6d24a5e 100644 --- a/licenses/vite@8.1.3/LICENSE.md +++ b/licenses/vite@8.2.1/LICENSE.md @@ -1219,6 +1219,13 @@ Repository: https://github.com/micromatch/is-glob --------------------------------------- +## is-reference +License: MIT +By: Rich Harris +Repository: https://github.com/Rich-Harris/is-reference + +--------------------------------------- + ## isexe, which License: ISC By: Isaac Z. Schlueter @@ -1249,7 +1256,7 @@ Repository: https://github.com/lydell/js-tokens > The MIT License (MIT) > -> Copyright (c) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 Simon Lydell +> Copyright (c) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025 Simon Lydell > > Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal @@ -2285,3 +2292,31 @@ Repository: https://github.com/websockets/ws > COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER > IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN > CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--------------------------------------- + +## zimmerframe +License: MIT +Repository: https://github.com/sveltejs/zimmerframe + +> MIT License +> +> Copyright (c) 2023 [these people](https://github.com/Rich-Harris/zimmerframe/graphs/contributors) +> +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in all +> copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +> SOFTWARE. diff --git a/licenses/vitest@4.1.9/LICENSE.md b/licenses/vitest@4.1.10/LICENSE.md similarity index 100% rename from licenses/vitest@4.1.9/LICENSE.md rename to licenses/vitest@4.1.10/LICENSE.md diff --git a/licenses/yaml@2.9.0/LICENSE b/licenses/yaml@2.9.0/LICENSE deleted file mode 100644 index e060aaa..0000000 --- a/licenses/yaml@2.9.0/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright Eemeli Aro - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/licenses/yargs@15.4.1/LICENSE b/licenses/yargs@15.4.1/LICENSE deleted file mode 100644 index b0145ca..0000000 --- a/licenses/yargs@15.4.1/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright 2010 James Halliday (mail@substack.net); Modified work Copyright 2014 Contributors (ben@npmjs.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/utils/scripts/copy-licenses.ts b/utils/scripts/copy-licenses.ts index 6ab5374..4a0f100 100644 --- a/utils/scripts/copy-licenses.ts +++ b/utils/scripts/copy-licenses.ts @@ -1,6 +1,5 @@ import { promises as fs } from "node:fs"; import path from "node:path"; -import { parse } from "yaml"; type PnpmLock = { lockfileVersion?: number; @@ -97,13 +96,92 @@ async function main(): Promise { async function readPnpmLock(): Promise { const raw = await fs.readFile(LOCKFILE_PATH, "utf8"); - const parsed = parse(raw); - if (!parsed || typeof parsed !== "object") { - throw new Error("Failed to parse pnpm-lock.yaml"); + return { + importers: extractTopLevelMappingKeys(raw, "importers"), + packages: extractTopLevelMappingKeys(raw, "packages"), + }; +} + +function extractTopLevelMappingKeys( + yaml: string, + sectionName: string, +): Record { + const result: Record = {}; + const lines = yaml.split(/\r?\n/); + + let inSection = false; + + for (const line of lines) { + if (!line.trim() || line.trimStart().startsWith("#")) continue; + + const indent = line.length - line.trimStart().length; + + if (indent === 0) { + inSection = line === `${sectionName}:`; + continue; + } + + if (!inSection || indent !== 2) continue; + + const trimmed = line.trim(); + const colonIndex = findYamlKeyColon(trimmed); + if (colonIndex < 0) continue; + + const rawKey = trimmed.slice(0, colonIndex).trim(); + if (!rawKey) continue; + + result[decodeYamlKey(rawKey)] = {}; } - return parsed as PnpmLock; + return result; +} + +function findYamlKeyColon(value: string): number { + let quote: "'" | '"' | null = null; + + for (let i = 0; i < value.length; i++) { + const ch = value[i]; + + if (quote === '"') { + if (ch === "\\") { + i++; + } else if (ch === '"') { + quote = null; + } + continue; + } + + if (quote === "'") { + if (ch === "'" && value[i + 1] === "'") { + i++; + } else if (ch === "'") { + quote = null; + } + continue; + } + + if (ch === '"' || ch === "'") { + quote = ch; + continue; + } + + if (ch === ":") return i; + } + + return -1; +} + +function decodeYamlKey(value: string): string { + if (value.startsWith('"') && value.endsWith('"')) { + return JSON.parse(value) as string; + } + + if (value.startsWith("'") && value.endsWith("'")) { + return value.slice(1, -1).replace(/''/g, "'"); + } + + return value; } async function getNodeModulesRoots(lock: PnpmLock): Promise { From f763af13bef799761d3c884fb0400fa9c350a604 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Sun, 9 Aug 2026 21:01:24 +0200 Subject: [PATCH 67/97] chore(deps): update mtp-transport digest to b067614 --- apps/tauri/src-tauri/Cargo.lock | 189 ++++++++++++++++++++++++++------ apps/tauri/src-tauri/Cargo.toml | 2 +- 2 files changed, 159 insertions(+), 32 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index 61fa603..9171fc5 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -924,7 +924,23 @@ dependencies = [ "cpufeatures 0.2.17", "curve25519-dalek-derive", "digest 0.10.7", - "fiat-crypto", + "fiat-crypto 0.2.9", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "curve25519-dalek-derive", + "digest 0.11.3", + "fiat-crypto 0.3.0", "rustc_version", "subtle", "zeroize", @@ -999,7 +1015,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid 0.9.6", - "pem-rfc7468", + "pem-rfc7468 0.7.0", "zeroize", ] @@ -1010,6 +1026,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a69dedd701da44b0536442edf09c81a64b0ab97a7a4a5e3d1971f00027cbc63d" dependencies = [ "const-oid 0.10.2", + "pem-rfc7468 1.0.0", "zeroize", ] @@ -1246,20 +1263,45 @@ dependencies = [ "signature 2.2.0", ] +[[package]] +name = "ed25519" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" +dependencies = [ + "pkcs8 0.11.0", + "signature 3.0.0", +] + [[package]] name = "ed25519-dalek" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ - "curve25519-dalek", - "ed25519", + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", "serde", "sha2 0.10.9", "subtle", "zeroize", ] +[[package]] +name = "ed25519-dalek" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de" +dependencies = [ + "curve25519-dalek 5.0.0", + "ed25519 3.0.0", + "serde", + "sha2 0.11.0", + "signature 3.0.0", + "subtle", + "zeroize", +] + [[package]] name = "embed-resource" version = "3.0.11" @@ -1406,6 +1448,12 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "fiat-crypto" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" + [[package]] name = "field-offset" version = "0.3.6" @@ -2822,12 +2870,12 @@ version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ "mtp-client", - "mtp-codec", - "mtp-common", - "mtp-crypto", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", "mtp-host", - "mtp-transport", - "mtp-type-map", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", "mtp-webserver", ] @@ -2836,10 +2884,10 @@ name = "mtp-client" version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ - "mtp-codec", - "mtp-common", - "mtp-crypto", - "mtp-transport", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", "rand 0.10.2", "tokio", ] @@ -2851,9 +2899,21 @@ source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7 dependencies = [ "base64 0.23.1", "byteorder", - "mtp-common", - "mtp-crypto", - "mtp-type-map", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "rand 0.10.2", +] + +[[package]] +name = "mtp-codec" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b#b067614a684eb1856bc5db7b3fd82148c036ce6b" +dependencies = [ + "base64 0.23.1", + "byteorder", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", + "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", "rand 0.10.2", ] @@ -2868,6 +2928,17 @@ dependencies = [ "wtransport", ] +[[package]] +name = "mtp-common" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b#b067614a684eb1856bc5db7b3fd82148c036ce6b" +dependencies = [ + "quinn", + "rustls", + "thiserror 2.0.19", + "wtransport", +] + [[package]] name = "mtp-crypto" version = "0.2.0" @@ -2875,7 +2946,7 @@ source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7 dependencies = [ "base64 0.23.1", "chacha20poly1305", - "ed25519-dalek", + "ed25519-dalek 2.2.0", "getrandom 0.4.3", "hkdf", "ml-dsa", @@ -2890,15 +2961,35 @@ dependencies = [ "zeroize", ] +[[package]] +name = "mtp-crypto" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b#b067614a684eb1856bc5db7b3fd82148c036ce6b" +dependencies = [ + "base64 0.23.1", + "chacha20poly1305", + "ed25519-dalek 3.0.0", + "getrandom 0.4.3", + "hkdf", + "ml-dsa", + "rand 0.10.2", + "rand_core 0.10.1", + "rustls", + "sha2 0.11.0", + "thiserror 2.0.19", + "tokio", + "zeroize", +] + [[package]] name = "mtp-host" version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ - "mtp-codec", - "mtp-common", - "mtp-crypto", - "mtp-transport", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", "rand 0.10.2", "tokio", "tracing", @@ -2911,9 +3002,27 @@ version = "0.2.0" source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" dependencies = [ "async-trait", - "mtp-codec", - "mtp-common", - "mtp-crypto", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "rcgen", + "rustls", + "rustls-native-certs", + "sha2 0.11.0", + "tokio", + "tracing", + "wtransport", +] + +[[package]] +name = "mtp-transport" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b#b067614a684eb1856bc5db7b3fd82148c036ce6b" +dependencies = [ + "async-trait", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", "rcgen", "rustls", "rustls-native-certs", @@ -2932,6 +3041,15 @@ dependencies = [ "serde_yaml", ] +[[package]] +name = "mtp-type-map" +version = "0.2.0" +source = "git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b#b067614a684eb1856bc5db7b3fd82148c036ce6b" +dependencies = [ + "serde", + "serde_yaml", +] + [[package]] name = "mtp-webserver" version = "0.2.0" @@ -2946,11 +3064,11 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", - "mtp-codec", - "mtp-common", - "mtp-crypto", + "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", "mtp-host", - "mtp-transport", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", "quinn", "rand 0.10.2", "rustls", @@ -3463,6 +3581,15 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pem-rfc7468" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -5370,12 +5497,12 @@ dependencies = [ [[package]] name = "tensamin" -version = "0.0.11" +version = "0.0.0" dependencies = [ "base64 0.22.1", "jni 0.22.4", "mtp", - "mtp-transport", + "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", "reqwest 0.12.28", "serde", "serde_json", @@ -6701,7 +6828,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 4.1.3", "rand_core 0.6.4", "serde", "zeroize", diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index 6bbca97..19fe954 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -25,7 +25,7 @@ base64 = "0.22" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } tokio = { version = "1", features = ["rt-multi-thread", "sync", "time"] } mtp = { git = "https://git.methanium.net/methanium/mtp.git", rev = "7182272e3edb0079d7b74b45b2f62a298d2fee22", features = ["client", "crypto"] } -mtp-transport = { git = "https://git.methanium.net/methanium/mtp.git", rev = "7182272e3edb0079d7b74b45b2f62a298d2fee22" } +mtp-transport = { git = "https://git.methanium.net/methanium/mtp.git", rev = "b067614a684eb1856bc5db7b3fd82148c036ce6b" } webpki-root-certs = "1" tauri-plugin-deep-link = "2" tauri-plugin-notification = "2" From dbb407606b68b85c9d4655ecb116fb4d3d7bb666 Mon Sep 17 00:00:00 2001 From: Alois Date: Mon, 10 Aug 2026 00:16:42 +0200 Subject: [PATCH 68/97] feat(markdown): migrate to methanium/ui's markdown --- apps/web/package.json | 1 - apps/web/src/components/modals/profile.tsx | 2 +- apps/web/vite.config.ts | 30 +- .../@codemirror_autocomplete@6.20.3/LICENSE | 21 - licenses/@codemirror_commands@6.10.4/LICENSE | 21 - .../@codemirror_lang-markdown@6.5.2/LICENSE | 21 - licenses/@codemirror_language@6.12.4/LICENSE | 21 - licenses/@codemirror_state@6.7.1/LICENSE | 21 - licenses/@codemirror_view@6.43.8/LICENSE | 21 - .../LICENSE | 0 licenses/@twemoji_api@17.0.3/LICENSE | 22 - licenses/THIRD_PARTY_NOTICES.md | 77 +- licenses/emojibase-data@17.0.0/LICENSE | 21 - licenses/sbom.cyclonedx.json | 262 +-- licenses/third-party-credits.json | 112 +- packages/chat/package.json | 1 - packages/chat/src/components/emojiPicker.tsx | 2 +- packages/chat/src/components/emojiRanks.ts | 2 +- packages/chat/src/components/input.tsx | 4 +- packages/chat/src/components/media.tsx | 6 +- packages/chat/src/components/message.tsx | 50 +- .../src/components/messageContextMenu.tsx | 2 +- packages/chat/src/components/replyBox.tsx | 13 +- packages/markdown/package.json | 30 - packages/markdown/src/emoji.test.ts | 138 -- packages/markdown/src/emoji.tsx | 50 - packages/markdown/src/emojiData.ts | 94 -- packages/markdown/src/input.tsx | 850 ---------- packages/markdown/src/markdown.tsx | 815 --------- packages/markdown/src/text.tsx | 30 - packages/markdown/todo.md | 1 - packages/markdown/tsconfig.json | 12 - packages/settings/package.json | 1 - packages/settings/src/pages/profile.tsx | 3 +- pnpm-lock.yaml | 1483 +++++++++++++++-- pnpm-workspace.yaml | 2 +- 36 files changed, 1355 insertions(+), 2887 deletions(-) delete mode 100644 licenses/@codemirror_autocomplete@6.20.3/LICENSE delete mode 100644 licenses/@codemirror_commands@6.10.4/LICENSE delete mode 100644 licenses/@codemirror_lang-markdown@6.5.2/LICENSE delete mode 100644 licenses/@codemirror_language@6.12.4/LICENSE delete mode 100644 licenses/@codemirror_state@6.7.1/LICENSE delete mode 100644 licenses/@codemirror_view@6.43.8/LICENSE rename licenses/{@methanium_ui@0.0.22 => @methanium_ui@0.0.28}/LICENSE (100%) delete mode 100644 licenses/@twemoji_api@17.0.3/LICENSE delete mode 100644 licenses/emojibase-data@17.0.0/LICENSE delete mode 100644 packages/markdown/package.json delete mode 100644 packages/markdown/src/emoji.test.ts delete mode 100644 packages/markdown/src/emoji.tsx delete mode 100644 packages/markdown/src/emojiData.ts delete mode 100644 packages/markdown/src/input.tsx delete mode 100644 packages/markdown/src/markdown.tsx delete mode 100644 packages/markdown/src/text.tsx delete mode 100644 packages/markdown/todo.md delete mode 100644 packages/markdown/tsconfig.json diff --git a/apps/web/package.json b/apps/web/package.json index e6c6bf8..107c6f7 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -23,7 +23,6 @@ "@tensamin/chat": "workspace:*", "@tensamin/crypto": "workspace:*", "@tensamin/hotkeys": "workspace:*", - "@tensamin/markdown": "workspace:*", "@tensamin/mtp": "workspace:*", "@tensamin/notifications": "workspace:*", "@tensamin/onboarding": "workspace:*", diff --git a/apps/web/src/components/modals/profile.tsx b/apps/web/src/components/modals/profile.tsx index edd83a6..6324ab5 100644 --- a/apps/web/src/components/modals/profile.tsx +++ b/apps/web/src/components/modals/profile.tsx @@ -1,6 +1,6 @@ import type { User } from "@tensamin/user/context"; import { Avatar, AvatarFallback, AvatarImage, Button } from "@methanium/ui"; -import Text from "@tensamin/markdown/text"; +import { Text } from "@methanium/ui/markdown"; import { ChevronDown, ChevronUp } from "lucide-react"; import { useState } from "react"; diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index bb41448..464f57b 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -1,4 +1,4 @@ -import { createReadStream, realpathSync, statSync } from "node:fs"; +import { createReadStream, statSync } from "node:fs"; import type { IncomingMessage, ServerResponse } from "node:http"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; @@ -11,11 +11,6 @@ import { methaniumUi } from "@methanium/ui/vite"; const host = process.env.TAURI_DEV_HOST; const appDir = dirname(fileURLToPath(import.meta.url)); -const markdownPackageDir = resolve(appDir, "../../packages/markdown"); - -function resolveMarkdownDependency(packageName: string): string { - return realpathSync(resolve(markdownPackageDir, "node_modules", packageName)); -} function deepFilterAssetHeaders(rootDir: string): Plugin { const serveModel = ( @@ -57,24 +52,6 @@ export default defineConfig({ clearScreen: false, resolve: { tsconfigPaths: true, - alias: [ - { - find: "@codemirror/commands", - replacement: resolveMarkdownDependency("@codemirror/commands"), - }, - { - find: "@codemirror/lang-markdown", - replacement: resolveMarkdownDependency("@codemirror/lang-markdown"), - }, - { - find: "@codemirror/state", - replacement: resolveMarkdownDependency("@codemirror/state"), - }, - { - find: "@codemirror/view", - replacement: resolveMarkdownDependency("@codemirror/view"), - }, - ], dedupe: [ "react", "react-dom", @@ -90,10 +67,6 @@ export default defineConfig({ "@tensamin/user", "@tensamin/tauri", "@tensamin/chat", - "@codemirror/commands", - "@codemirror/lang-markdown", - "@codemirror/state", - "@codemirror/view", ], }, server: { @@ -133,7 +106,6 @@ export default defineConfig({ "@tensamin/crypto", "@tensamin/crypto/context", "@tensamin/hotkeys", - "@tensamin/markdown", "@tensamin/mtp", "@tensamin/notifications", "@tensamin/onboarding", diff --git a/licenses/@codemirror_autocomplete@6.20.3/LICENSE b/licenses/@codemirror_autocomplete@6.20.3/LICENSE deleted file mode 100644 index 9a91f48..0000000 --- a/licenses/@codemirror_autocomplete@6.20.3/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (C) 2018-2021 by Marijn Haverbeke and others - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/licenses/@codemirror_commands@6.10.4/LICENSE b/licenses/@codemirror_commands@6.10.4/LICENSE deleted file mode 100644 index 9a91f48..0000000 --- a/licenses/@codemirror_commands@6.10.4/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (C) 2018-2021 by Marijn Haverbeke and others - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/licenses/@codemirror_lang-markdown@6.5.2/LICENSE b/licenses/@codemirror_lang-markdown@6.5.2/LICENSE deleted file mode 100644 index 9a91f48..0000000 --- a/licenses/@codemirror_lang-markdown@6.5.2/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (C) 2018-2021 by Marijn Haverbeke and others - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/licenses/@codemirror_language@6.12.4/LICENSE b/licenses/@codemirror_language@6.12.4/LICENSE deleted file mode 100644 index 9a91f48..0000000 --- a/licenses/@codemirror_language@6.12.4/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (C) 2018-2021 by Marijn Haverbeke and others - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/licenses/@codemirror_state@6.7.1/LICENSE b/licenses/@codemirror_state@6.7.1/LICENSE deleted file mode 100644 index 9a91f48..0000000 --- a/licenses/@codemirror_state@6.7.1/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (C) 2018-2021 by Marijn Haverbeke and others - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/licenses/@codemirror_view@6.43.8/LICENSE b/licenses/@codemirror_view@6.43.8/LICENSE deleted file mode 100644 index 9a91f48..0000000 --- a/licenses/@codemirror_view@6.43.8/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (C) 2018-2021 by Marijn Haverbeke and others - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/licenses/@methanium_ui@0.0.22/LICENSE b/licenses/@methanium_ui@0.0.28/LICENSE similarity index 100% rename from licenses/@methanium_ui@0.0.22/LICENSE rename to licenses/@methanium_ui@0.0.28/LICENSE diff --git a/licenses/@twemoji_api@17.0.3/LICENSE b/licenses/@twemoji_api@17.0.3/LICENSE deleted file mode 100644 index d2e3436..0000000 --- a/licenses/@twemoji_api@17.0.3/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2022–present Jason Sofonia & Justine De Caires -Copyright (c) 2014–2021 Twitter - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/THIRD_PARTY_NOTICES.md b/licenses/THIRD_PARTY_NOTICES.md index bda5f0c..2094186 100644 --- a/licenses/THIRD_PARTY_NOTICES.md +++ b/licenses/THIRD_PARTY_NOTICES.md @@ -2,60 +2,6 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules folders. -## @codemirror/autocomplete@6.20.3 - -- License: MIT -- Repository: git+https://code.haverbeke.berlin/codemirror/autocomplete.git -- Description: Autocompletion for the CodeMirror code editor -- Included files: LICENSE -- Folder: `licenses/@codemirror_autocomplete@6.20.3` -- Source package dir: `packages/markdown/node_modules/@codemirror/autocomplete` - -## @codemirror/commands@6.10.4 - -- License: MIT -- Repository: git+https://code.haverbeke.berlin/codemirror/commands.git -- Description: Collection of editing commands for the CodeMirror code editor -- Included files: LICENSE -- Folder: `licenses/@codemirror_commands@6.10.4` -- Source package dir: `packages/markdown/node_modules/@codemirror/commands` - -## @codemirror/lang-markdown@6.5.2 - -- License: MIT -- Repository: git+https://code.haverbeke.berlin/codemirror/lang-markdown.git -- Description: Markdown language support for the CodeMirror code editor -- Included files: LICENSE -- Folder: `licenses/@codemirror_lang-markdown@6.5.2` -- Source package dir: `packages/markdown/node_modules/@codemirror/lang-markdown` - -## @codemirror/language@6.12.4 - -- License: MIT -- Repository: git+https://code.haverbeke.berlin/codemirror/language.git -- Description: Language support infrastructure for the CodeMirror code editor -- Included files: LICENSE -- Folder: `licenses/@codemirror_language@6.12.4` -- Source package dir: `packages/markdown/node_modules/@codemirror/language` - -## @codemirror/state@6.7.1 - -- License: MIT -- Repository: git+https://code.haverbeke.berlin/codemirror/state.git -- Description: Editor state data structures for the CodeMirror code editor -- Included files: LICENSE -- Folder: `licenses/@codemirror_state@6.7.1` -- Source package dir: `packages/markdown/node_modules/@codemirror/state` - -## @codemirror/view@6.43.8 - -- License: MIT -- Repository: git+https://code.haverbeke.berlin/codemirror/view.git -- Description: DOM view component for the CodeMirror code editor -- Included files: LICENSE -- Folder: `licenses/@codemirror_view@6.43.8` -- Source package dir: `packages/markdown/node_modules/@codemirror/view` - ## @eslint/js@10.0.1 - License: MIT @@ -84,11 +30,11 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@livekit_components-react@2.9.23` - Source package dir: `packages/call/node_modules/@livekit/components-react` -## @methanium/ui@0.0.22 +## @methanium/ui@0.0.28 - License: UNKNOWN - Included files: LICENSE -- Folder: `licenses/@methanium_ui@0.0.22` +- Folder: `licenses/@methanium_ui@0.0.28` - Source package dir: `apps/tauri/node_modules/@methanium/ui` ## @tailwindcss/vite@4.3.3 @@ -197,16 +143,6 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@tauri-apps_plugin-notification@2.3.3` - Source package dir: `packages/notifications/node_modules/@tauri-apps/plugin-notification` -## @twemoji/api@17.0.3 - -- License: MIT AND CC-BY-4.0 -- Homepage: https://github.com/jdecked/twemoji -- Repository: git://github.com/jdecked/twemoji.git -- Description: A Unicode standard based way to implement emoji across all platforms. -- Included files: LICENSE -- Folder: `licenses/@twemoji_api@17.0.3` -- Source package dir: `packages/markdown/node_modules/@twemoji/api` - ## @types/node@26.2.0 - License: MIT @@ -305,15 +241,6 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/electron-builder@26.15.3` - Source package dir: `apps/electron/node_modules/electron-builder` -## emojibase-data@17.0.0 - -- License: MIT -- Repository: git@github.com:milesj/emojibase.git -- Description: Evergreen emoji datasets. -- Included files: LICENSE -- Folder: `licenses/emojibase-data@17.0.0` -- Source package dir: `packages/markdown/node_modules/emojibase-data` - ## esbuild@0.28.1 - License: MIT diff --git a/licenses/emojibase-data@17.0.0/LICENSE b/licenses/emojibase-data@17.0.0/LICENSE deleted file mode 100644 index 3e21d0b..0000000 --- a/licenses/emojibase-data@17.0.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017-2019 Miles Johnson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/licenses/sbom.cyclonedx.json b/licenses/sbom.cyclonedx.json index 4075c6b..ebb655c 100644 --- a/licenses/sbom.cyclonedx.json +++ b/licenses/sbom.cyclonedx.json @@ -3,7 +3,7 @@ "specVersion": "1.5", "version": 1, "metadata": { - "timestamp": "2026-08-09T18:16:10.177Z", + "timestamp": "2026-08-09T22:09:04.469Z", "tools": [ { "vendor": "OpenAI", @@ -16,192 +16,6 @@ } }, "components": [ - { - "type": "library", - "bomRef": "pkg:npm/%40codemirror/autocomplete@6.20.3", - "name": "@codemirror/autocomplete", - "version": "6.20.3", - "purl": "pkg:npm/%40codemirror/autocomplete@6.20.3", - "description": "Autocompletion for the CodeMirror code editor", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "git+https://code.haverbeke.berlin/codemirror/autocomplete.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@codemirror_autocomplete@6.20.3" - }, - { - "name": "local:sourcePackageDir", - "value": "packages/markdown/node_modules/@codemirror/autocomplete" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40codemirror/commands@6.10.4", - "name": "@codemirror/commands", - "version": "6.10.4", - "purl": "pkg:npm/%40codemirror/commands@6.10.4", - "description": "Collection of editing commands for the CodeMirror code editor", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "git+https://code.haverbeke.berlin/codemirror/commands.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@codemirror_commands@6.10.4" - }, - { - "name": "local:sourcePackageDir", - "value": "packages/markdown/node_modules/@codemirror/commands" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40codemirror/lang-markdown@6.5.2", - "name": "@codemirror/lang-markdown", - "version": "6.5.2", - "purl": "pkg:npm/%40codemirror/lang-markdown@6.5.2", - "description": "Markdown language support for the CodeMirror code editor", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "git+https://code.haverbeke.berlin/codemirror/lang-markdown.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@codemirror_lang-markdown@6.5.2" - }, - { - "name": "local:sourcePackageDir", - "value": "packages/markdown/node_modules/@codemirror/lang-markdown" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40codemirror/language@6.12.4", - "name": "@codemirror/language", - "version": "6.12.4", - "purl": "pkg:npm/%40codemirror/language@6.12.4", - "description": "Language support infrastructure for the CodeMirror code editor", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "git+https://code.haverbeke.berlin/codemirror/language.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@codemirror_language@6.12.4" - }, - { - "name": "local:sourcePackageDir", - "value": "packages/markdown/node_modules/@codemirror/language" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40codemirror/state@6.7.1", - "name": "@codemirror/state", - "version": "6.7.1", - "purl": "pkg:npm/%40codemirror/state@6.7.1", - "description": "Editor state data structures for the CodeMirror code editor", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "git+https://code.haverbeke.berlin/codemirror/state.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@codemirror_state@6.7.1" - }, - { - "name": "local:sourcePackageDir", - "value": "packages/markdown/node_modules/@codemirror/state" - } - ] - }, - { - "type": "library", - "bomRef": "pkg:npm/%40codemirror/view@6.43.8", - "name": "@codemirror/view", - "version": "6.43.8", - "purl": "pkg:npm/%40codemirror/view@6.43.8", - "description": "DOM view component for the CodeMirror code editor", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "git+https://code.haverbeke.berlin/codemirror/view.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@codemirror_view@6.43.8" - }, - { - "name": "local:sourcePackageDir", - "value": "packages/markdown/node_modules/@codemirror/view" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/%40eslint/js@10.0.1", @@ -304,15 +118,15 @@ }, { "type": "library", - "bomRef": "pkg:npm/%40methanium/ui@0.0.22", + "bomRef": "pkg:npm/%40methanium/ui@0.0.28", "name": "@methanium/ui", - "version": "0.0.22", - "purl": "pkg:npm/%40methanium/ui@0.0.22", + "version": "0.0.28", + "purl": "pkg:npm/%40methanium/ui@0.0.28", "externalReferences": [], "properties": [ { "name": "local:licenseFolder", - "value": "licenses/@methanium_ui@0.0.22" + "value": "licenses/@methanium_ui@0.0.28" }, { "name": "local:sourcePackageDir", @@ -692,41 +506,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/%40twemoji/api@17.0.3", - "name": "@twemoji/api", - "version": "17.0.3", - "purl": "pkg:npm/%40twemoji/api@17.0.3", - "description": "A Unicode standard based way to implement emoji across all platforms.", - "licenses": [ - { - "license": { - "name": "MIT AND CC-BY-4.0" - } - } - ], - "externalReferences": [ - { - "type": "website", - "url": "https://github.com/jdecked/twemoji" - }, - { - "type": "vcs", - "url": "git://github.com/jdecked/twemoji.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@twemoji_api@17.0.3" - }, - { - "name": "local:sourcePackageDir", - "value": "packages/markdown/node_modules/@twemoji/api" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/%40types/node@26.2.0", @@ -1069,37 +848,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/emojibase-data@17.0.0", - "name": "emojibase-data", - "version": "17.0.0", - "purl": "pkg:npm/emojibase-data@17.0.0", - "description": "Evergreen emoji datasets.", - "licenses": [ - { - "license": { - "id": "MIT" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "git@github.com:milesj/emojibase.git" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/emojibase-data@17.0.0" - }, - { - "name": "local:sourcePackageDir", - "value": "packages/markdown/node_modules/emojibase-data" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/esbuild@0.28.1", diff --git a/licenses/third-party-credits.json b/licenses/third-party-credits.json index 9f4b971..5ea2d3d 100644 --- a/licenses/third-party-credits.json +++ b/licenses/third-party-credits.json @@ -1,85 +1,7 @@ { - "generatedAt": "2026-08-09T18:16:10.172Z", - "packageCount": 60, + "generatedAt": "2026-08-09T22:09:04.466Z", + "packageCount": 52, "packages": [ - { - "name": "@codemirror/autocomplete", - "version": "6.20.3", - "license": "MIT", - "homepage": null, - "repository": "git+https://code.haverbeke.berlin/codemirror/autocomplete.git", - "description": "Autocompletion for the CodeMirror code editor", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@codemirror_autocomplete@6.20.3", - "sourcePackageDir": "packages/markdown/node_modules/@codemirror/autocomplete" - }, - { - "name": "@codemirror/commands", - "version": "6.10.4", - "license": "MIT", - "homepage": null, - "repository": "git+https://code.haverbeke.berlin/codemirror/commands.git", - "description": "Collection of editing commands for the CodeMirror code editor", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@codemirror_commands@6.10.4", - "sourcePackageDir": "packages/markdown/node_modules/@codemirror/commands" - }, - { - "name": "@codemirror/lang-markdown", - "version": "6.5.2", - "license": "MIT", - "homepage": null, - "repository": "git+https://code.haverbeke.berlin/codemirror/lang-markdown.git", - "description": "Markdown language support for the CodeMirror code editor", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@codemirror_lang-markdown@6.5.2", - "sourcePackageDir": "packages/markdown/node_modules/@codemirror/lang-markdown" - }, - { - "name": "@codemirror/language", - "version": "6.12.4", - "license": "MIT", - "homepage": null, - "repository": "git+https://code.haverbeke.berlin/codemirror/language.git", - "description": "Language support infrastructure for the CodeMirror code editor", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@codemirror_language@6.12.4", - "sourcePackageDir": "packages/markdown/node_modules/@codemirror/language" - }, - { - "name": "@codemirror/state", - "version": "6.7.1", - "license": "MIT", - "homepage": null, - "repository": "git+https://code.haverbeke.berlin/codemirror/state.git", - "description": "Editor state data structures for the CodeMirror code editor", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@codemirror_state@6.7.1", - "sourcePackageDir": "packages/markdown/node_modules/@codemirror/state" - }, - { - "name": "@codemirror/view", - "version": "6.43.8", - "license": "MIT", - "homepage": null, - "repository": "git+https://code.haverbeke.berlin/codemirror/view.git", - "description": "DOM view component for the CodeMirror code editor", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@codemirror_view@6.43.8", - "sourcePackageDir": "packages/markdown/node_modules/@codemirror/view" - }, { "name": "@eslint/js", "version": "10.0.1", @@ -121,7 +43,7 @@ }, { "name": "@methanium/ui", - "version": "0.0.22", + "version": "0.0.28", "license": "UNKNOWN", "homepage": null, "repository": null, @@ -129,7 +51,7 @@ "files": [ "LICENSE" ], - "licenseFolder": "licenses/@methanium_ui@0.0.22", + "licenseFolder": "licenses/@methanium_ui@0.0.28", "sourcePackageDir": "apps/tauri/node_modules/@methanium/ui" }, { @@ -277,19 +199,6 @@ "licenseFolder": "licenses/@tauri-apps_plugin-notification@2.3.3", "sourcePackageDir": "packages/notifications/node_modules/@tauri-apps/plugin-notification" }, - { - "name": "@twemoji/api", - "version": "17.0.3", - "license": "MIT AND CC-BY-4.0", - "homepage": "https://github.com/jdecked/twemoji", - "repository": "git://github.com/jdecked/twemoji.git", - "description": "A Unicode standard based way to implement emoji across all platforms.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/@twemoji_api@17.0.3", - "sourcePackageDir": "packages/markdown/node_modules/@twemoji/api" - }, { "name": "@types/node", "version": "26.2.0", @@ -421,19 +330,6 @@ "licenseFolder": "licenses/electron-builder@26.15.3", "sourcePackageDir": "apps/electron/node_modules/electron-builder" }, - { - "name": "emojibase-data", - "version": "17.0.0", - "license": "MIT", - "homepage": null, - "repository": "git@github.com:milesj/emojibase.git", - "description": "Evergreen emoji datasets.", - "files": [ - "LICENSE" - ], - "licenseFolder": "licenses/emojibase-data@17.0.0", - "sourcePackageDir": "packages/markdown/node_modules/emojibase-data" - }, { "name": "esbuild", "version": "0.28.1", diff --git a/packages/chat/package.json b/packages/chat/package.json index 0e4f42f..d164529 100644 --- a/packages/chat/package.json +++ b/packages/chat/package.json @@ -24,7 +24,6 @@ "@tensamin/cache": "workspace:*", "@tensamin/crypto": "workspace:*", "@tensamin/hotkeys": "workspace:*", - "@tensamin/markdown": "workspace:*", "@tensamin/mtp": "workspace:*", "@tensamin/shared": "workspace:*", "@tensamin/storage": "workspace:*", diff --git a/packages/chat/src/components/emojiPicker.tsx b/packages/chat/src/components/emojiPicker.tsx index 7f7ff0e..ed8f2a1 100644 --- a/packages/chat/src/components/emojiPicker.tsx +++ b/packages/chat/src/components/emojiPicker.tsx @@ -1,5 +1,5 @@ import { Button } from "@methanium/ui"; -import Emoji from "@tensamin/markdown/emoji"; +import { Emoji } from "@methanium/ui/markdown"; import { getRecentEmojis, useEmojiRanks } from "./emojiRanks"; export default function EmojiPicker({ diff --git a/packages/chat/src/components/emojiRanks.ts b/packages/chat/src/components/emojiRanks.ts index 874c125..a30deb5 100644 --- a/packages/chat/src/components/emojiRanks.ts +++ b/packages/chat/src/components/emojiRanks.ts @@ -1,6 +1,6 @@ import { useStorage } from "@tensamin/storage/context"; import { useCallback, useEffect, useState } from "react"; -import { normalizeShortcode } from "@tensamin/markdown/emoji"; +import { normalizeShortcode } from "@methanium/ui/markdown"; const RANKS_CHANGED_EVENT = "tensamin-reaction-ranks-changed"; let recordQueue = Promise.resolve(); diff --git a/packages/chat/src/components/input.tsx b/packages/chat/src/components/input.tsx index e54235d..28752f0 100644 --- a/packages/chat/src/components/input.tsx +++ b/packages/chat/src/components/input.tsx @@ -1,4 +1,4 @@ -import Input, { type InputController } from "@tensamin/markdown/input"; +import { Input, type InputController } from "@methanium/ui/markdown"; import { Card, CardHeader, @@ -276,7 +276,7 @@ export default function InputComponent({
)}
@@ -388,20 +387,21 @@ function MessageComponent({ )} {editing ? (
- { - if (!editDraft.trim()) return; - if (editDraft !== message.Content) { - void submitEditMessage(editDraft); - } - onSetEditing(false); - }} - /> + + { + if (!editDraft.trim()) return; + if (editDraft !== message.Content) { + void submitEditMessage(editDraft); + } + onSetEditing(false); + }} + /> +
) : ( -
+
{isValidURL ? ( ) : ( - - )} - {message.Edited && ( -

- (edited) -

+
+ +
)}
)} diff --git a/packages/chat/src/components/messageContextMenu.tsx b/packages/chat/src/components/messageContextMenu.tsx index 227afbb..481e599 100644 --- a/packages/chat/src/components/messageContextMenu.tsx +++ b/packages/chat/src/components/messageContextMenu.tsx @@ -44,7 +44,7 @@ import type { Ref, } from "react"; import { useChat } from "../context"; -import Emoji from "@tensamin/markdown/emoji"; +import { Emoji } from "@methanium/ui/markdown"; import EmojiPicker from "./emojiPicker"; import { getRecentEmojis, useEmojiRanks } from "./emojiRanks"; diff --git a/packages/chat/src/components/replyBox.tsx b/packages/chat/src/components/replyBox.tsx index 03df6b0..82417d0 100644 --- a/packages/chat/src/components/replyBox.tsx +++ b/packages/chat/src/components/replyBox.tsx @@ -6,7 +6,7 @@ import { cn, Skeleton, } from "@methanium/ui"; -import Text from "@tensamin/markdown/text"; +import { Text } from "@methanium/ui/markdown"; import type { User } from "@tensamin/user/context"; import Wrapper from "@tensamin/user/wrapper"; import { Forward, X } from "lucide-react"; @@ -77,12 +77,11 @@ export default function ReplyBox({ ) : null} {content !== undefined && (
- - {edited && ( -

- (edited) -

- )} +
)} diff --git a/packages/markdown/package.json b/packages/markdown/package.json deleted file mode 100644 index 247d715..0000000 --- a/packages/markdown/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "@tensamin/markdown", - "private": true, - "version": "0.0.0", - "type": "module", - "exports": { - "./text": "./src/text.tsx", - "./input": "./src/input.tsx", - "./emoji": "./src/emoji.tsx" - }, - "scripts": { - "format": "pnpm exec prettier --write .", - "lint": "eslint src", - "build": "tsc -p tsconfig.json --noEmit" - }, - "dependencies": { - "@codemirror/autocomplete": "^6.20.3", - "@codemirror/commands": "^6.10.4", - "@codemirror/lang-markdown": "^6.5.2", - "@codemirror/language": "^6.12.4", - "@codemirror/state": "^6.7.1", - "@codemirror/view": "^6.43.8", - "@methanium/ui": "*", - "@twemoji/api": "^17.0.3", - "emojibase-data": "^17.0.0", - "lucide-react": "^1.30.0", - "react": "^19.2.8", - "react-dom": "^19.2.8" - } -} diff --git a/packages/markdown/src/emoji.test.ts b/packages/markdown/src/emoji.test.ts deleted file mode 100644 index 2a94b81..0000000 --- a/packages/markdown/src/emoji.test.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; -import type { ReactNode } from "react"; - -vi.mock("@methanium/ui", () => ({ - Tooltip: ({ children }: { children: ReactNode }) => children, - TooltipContent: ({ children }: { children: ReactNode }) => children, - TooltipTrigger: ({ render }: { render: ReactNode }) => render, -})); -import { EditorState } from "@codemirror/state"; -import { CompletionContext } from "@codemirror/autocomplete"; -import { markdown } from "@codemirror/lang-markdown"; -import { normalizeShortcode, resolveEmoji, searchEmojis } from "./emojiData"; -import { parseEmojiText, parseInlineNodes } from "./markdown"; -import { - createEmojiCompletionSource, - findEmojiRanges, - MAX_RENDERED_EMOJI_OPTIONS, -} from "./input"; - -describe("emoji shortcodes", () => { - it("normalizes aliases to their canonical shortcode", () => { - expect(normalizeShortcode(":flame:")).toBe(":fire:"); - expect(normalizeShortcode("+1")).toBe(":thumbsup:"); - }); - - it("resolves every search result to a Twemoji hexcode", () => { - const results = searchEmojis("fire"); - expect(results[0]?.shortcode).toBe(":fire:"); - expect(results.every((emoji) => emoji.hexcode.length > 0)).toBe(true); - }); - - it("shows all emojis for an empty query", () => { - expect(searchEmojis("").length).toBeGreaterThan(1000); - }); - - it("bounds the number of mounted autocomplete rows", () => { - expect(MAX_RENDERED_EMOJI_OPTIONS).toBeLessThanOrEqual(100); - }); - - it("parses known shortcodes and preserves unknown ones", () => { - expect(parseEmojiText("a :fire: b :not_an_emoji:")).toEqual([ - { type: "text", value: "a " }, - { type: "emoji", shortcode: ":fire:" }, - { type: "text", value: " b :not_an_emoji:" }, - ]); - }); - - it("recognizes a valid shortcode sharing an unknown closing colon", () => { - expect(parseEmojiText(":bla:thumbsup:")).toEqual([ - { type: "text", value: ":bla" }, - { type: "emoji", shortcode: ":thumbsup:" }, - ]); - - const state = EditorState.create({ - doc: ":bla:thumbsup:", - extensions: [markdown()], - }); - expect(findEmojiRanges(state)[0]?.from).toBe(4); - }); - - it("does not parse underscores inside emoji shortcodes as emphasis", () => { - expect(parseInlineNodes("before :white_check_mark: after")).toEqual([ - { type: "text", value: "before " }, - { type: "emoji", shortcode: ":white_check_mark:" }, - { type: "text", value: " after" }, - ]); - }); - - it("contains the picker defaults", () => { - expect(resolveEmoji(":thumbsup:")).toBeDefined(); - expect(resolveEmoji(":white_check_mark:")).toBeDefined(); - }); - - it("finds completed emoji shortcodes in editor state", () => { - const state = EditorState.create({ - doc: "before :fire: after :not_an_emoji:", - extensions: [markdown()], - }); - - expect( - findEmojiRanges(state).map(({ from, shortcode, to }) => ({ - from, - shortcode, - to, - })), - ).toEqual([{ from: 7, shortcode: ":fire:", to: 13 }]); - }); - - it("does not replace emoji shortcodes inside code", () => { - const state = EditorState.create({ - doc: "`:fire:`\n\n```\n:fire:\n```\n\n:fire:", - extensions: [markdown()], - }); - - expect(findEmojiRanges(state)).toHaveLength(1); - expect(findEmojiRanges(state)[0]?.from).toBe(26); - }); - - it("ranks frequently used emojis first for a bare colon", async () => { - const state = EditorState.create({ doc: ":", extensions: [markdown()] }); - const result = await createEmojiCompletionSource({ - ":fire:": 50, - ":thumbsup:": 2, - })(new CompletionContext(state, 1, false)); - - expect(result?.options[0]?.displayLabel).toBe(":fire:"); - expect(result?.options[1]?.displayLabel).toBe(":thumbsup:"); - }); - - it("keeps typed relevance above usage frequency", async () => { - const state = EditorState.create({ - doc: ":fire", - extensions: [markdown()], - }); - const result = await createEmojiCompletionSource({ - ":fire_engine:": 10000, - ":fire:": 1, - })(new CompletionContext(state, 5, false)); - - expect(result?.options[0]?.displayLabel).toBe(":fire:"); - expect(result?.options[0]?.boost).toBeGreaterThan( - result?.options[1]?.boost ?? 0, - ); - }); - - it("merges alias frequencies into canonical completions", async () => { - const state = EditorState.create({ doc: ":", extensions: [markdown()] }); - const result = await createEmojiCompletionSource({ - ":fire:": 2, - ":flame:": 3, - })(new CompletionContext(state, 1, false)); - const fire = result?.options.find( - (option) => option.displayLabel === ":fire:", - ); - - expect(fire?.boost).toBe(15); - }); -}); diff --git a/packages/markdown/src/emoji.tsx b/packages/markdown/src/emoji.tsx deleted file mode 100644 index c0eb397..0000000 --- a/packages/markdown/src/emoji.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import twemoji from "@twemoji/api"; -import { Tooltip, TooltipContent, TooltipTrigger } from "@methanium/ui"; -import { resolveEmoji } from "./emojiData"; - -export { - emojis, - findEmojiShortcodes, - normalizeShortcode, - resolveEmoji, - searchEmojis, -} from "./emojiData"; -export type { EmojiDefinition } from "./emojiData"; - -export function getEmojiUrl(shortcode: string): string | undefined { - const emoji = resolveEmoji(shortcode); - return emoji ? `${twemoji.base}svg/${emoji.hexcode}.svg` : undefined; -} - -export default function Emoji({ - className = "h-6 w-6", - shortcode, - tooltip = true, -}: { - className?: string; - shortcode: string; - tooltip?: boolean; -}) { - const emoji = resolveEmoji(shortcode); - if (!emoji) return {shortcode}; - - const image = ( - {emoji.shortcode} - ); - - if (!tooltip) return image; - - return ( - - - {emoji.shortcode} - - ); -} diff --git a/packages/markdown/src/emojiData.ts b/packages/markdown/src/emojiData.ts deleted file mode 100644 index 158b5b0..0000000 --- a/packages/markdown/src/emojiData.ts +++ /dev/null @@ -1,94 +0,0 @@ -import shortcodeData from "emojibase-data/en/shortcodes/joypixels.json"; - -export type EmojiDefinition = { - aliases: readonly string[]; - hexcode: string; - name: string; - shortcode: string; -}; - -function normalizeName(value: string) { - return value - .trim() - .replace(/^:+|:+$/g, "") - .toLowerCase(); -} - -export const emojis: readonly EmojiDefinition[] = Object.entries( - shortcodeData as Record, -).map(([hexcode, value]) => { - const aliases = Array.isArray(value) ? value : [value]; - const name = aliases[0]; - - return { - aliases, - hexcode: hexcode.toLowerCase().replaceAll("_", "-"), - name, - shortcode: `:${name}:`, - }; -}); - -const emojiByName = new Map(); -for (const emoji of emojis) { - for (const alias of emoji.aliases) { - emojiByName.set(normalizeName(alias), emoji); - } -} - -export function resolveEmoji(value: string): EmojiDefinition | undefined { - return emojiByName.get(normalizeName(value)); -} - -export function normalizeShortcode(value: string): string | undefined { - return resolveEmoji(value)?.shortcode; -} - -export function findEmojiShortcodes(value: string) { - const matches: Array<{ - emoji: EmojiDefinition; - from: number; - to: number; - }> = []; - let searchFrom = 0; - - while (searchFrom < value.length) { - const from = value.indexOf(":", searchFrom); - if (from === -1) break; - - const candidate = value.slice(from).match(/^:([a-z0-9_+-]+):/i); - if (!candidate) { - searchFrom = from + 1; - continue; - } - - const emoji = resolveEmoji(candidate[1]); - if (!emoji) { - // The closing colon may also open the next valid shortcode. - searchFrom = from + candidate[0].length - 1; - continue; - } - - const to = from + candidate[0].length; - matches.push({ emoji, from, to }); - searchFrom = to; - } - - return matches; -} - -export function searchEmojis(query: string): EmojiDefinition[] { - const normalizedQuery = normalizeName(query); - if (!normalizedQuery) return [...emojis]; - - return emojis - .map((emoji) => { - const names = emoji.aliases.map(normalizeName); - const exact = names.includes(normalizedQuery); - const prefix = names.some((name) => name.startsWith(normalizedQuery)); - const contains = names.some((name) => name.includes(normalizedQuery)); - return { emoji, rank: exact ? 0 : prefix ? 1 : contains ? 2 : 3 }; - }) - .filter(({ rank }) => rank < 3) - .sort((a, b) => a.rank - b.rank || a.emoji.name.localeCompare(b.emoji.name)) - .map(({ emoji }) => emoji); -} diff --git a/packages/markdown/src/input.tsx b/packages/markdown/src/input.tsx deleted file mode 100644 index e16c84d..0000000 --- a/packages/markdown/src/input.tsx +++ /dev/null @@ -1,850 +0,0 @@ -import { markdown } from "@codemirror/lang-markdown"; -import { syntaxTree } from "@codemirror/language"; -import { - acceptCompletion, - autocompletion, - completionStatus, - pickedCompletion, - startCompletion, - type Completion, - type CompletionContext, - type CompletionResult, -} from "@codemirror/autocomplete"; -import { - EditorState, - EditorSelection, - Annotation, - Compartment, - Prec, - Transaction, - type Extension, - type Range, - type SelectionRange, -} from "@codemirror/state"; -import { - Decoration, - EditorView, - keymap, - placeholder, - ViewPlugin, - WidgetType, - type DecorationSet, - type KeyBinding, - type ViewUpdate, -} from "@codemirror/view"; -import { - defaultKeymap, - history, - historyKeymap, - indentWithTab, -} from "@codemirror/commands"; -import { useEffect, useRef } from "react"; -import type { CSSProperties } from "react"; -import { createRoot, type Root } from "react-dom/client"; - -import { collectInlineRanges, ensureMarkdownStyles } from "./markdown"; -import Emoji, { - findEmojiShortcodes, - getEmojiUrl, - resolveEmoji, - searchEmojis, -} from "./emoji"; - -export const MAX_RENDERED_EMOJI_OPTIONS = 100; - -export type InputController = { - focus: () => void; - hasFocus: () => boolean; - insertText: (text: string) => void; -}; - -export type InputProps = { - ref?: HTMLDivElement; - placeholder?: string; - value: string; - setValue: (value: string) => void; - onSubmit?: () => void; - invertEnterBehavior?: boolean; - styled?: boolean; - fontSize?: CSSProperties["fontSize"]; - paddingX?: CSSProperties["padding"]; - paddingY?: CSSProperties["padding"]; - className?: string; - emojiFrequencies?: Readonly>; - onEmojiSelect?: (shortcode: string) => void; - autoFocus?: boolean; - onControllerChange?: (controller: InputController | null) => void; -}; - -function toCssLength(value: CSSProperties["padding"]): string | undefined { - if (value === undefined) { - return undefined; - } - - return typeof value === "number" ? `${value}px` : value; -} - -function toCssPadding( - vertical: CSSProperties["padding"], - horizontal: CSSProperties["padding"], - styled: boolean, -): string { - const defaultVertical = styled ? "0.25rem" : "0"; - const defaultHorizontal = styled ? "0.625rem" : "0"; - - return `${toCssLength(vertical) ?? defaultVertical} ${toCssLength(horizontal) ?? defaultHorizontal}`; -} - -const hiddenTokenDecoration = Decoration.mark({ class: "tm-md-hidden-token" }); -const strongDecoration = Decoration.mark({ class: "tm-md-strong" }); -const emDecoration = Decoration.mark({ class: "tm-md-em" }); -const delDecoration = Decoration.mark({ class: "tm-md-del" }); -const codeDecoration = Decoration.mark({ class: "tm-md-code" }); -const linkDecoration = Decoration.mark({ class: "tm-md-link" }); -const codeLineDecoration = Decoration.line({ class: "tm-md-code-line" }); -const externalValueSync = Annotation.define(); -const widgetRoots = new WeakMap(); - -type EmojiRange = { - from: number; - shortcode: string; - to: number; - url: string; -}; - -class EmojiWidget extends WidgetType { - readonly shortcode: string; - readonly url: string; - - constructor(shortcode: string, url: string) { - super(); - this.shortcode = shortcode; - this.url = url; - } - - eq(other: EmojiWidget) { - return other.shortcode === this.shortcode && other.url === this.url; - } - - toDOM() { - const container = document.createElement("span"); - const root = createRoot(container); - root.render( - , - ); - widgetRoots.set(container, root); - return container; - } - - destroy(dom: HTMLElement) { - widgetRoots.get(dom)?.unmount(); - widgetRoots.delete(dom); - } - - ignoreEvent() { - return true; - } -} - -function codeRanges(state: EditorState) { - const ranges: Array<{ from: number; to: number }> = []; - - syntaxTree(state).iterate({ - enter(node) { - if ( - node.name === "InlineCode" || - node.name === "FencedCode" || - node.name === "CodeBlock" - ) { - ranges.push({ from: node.from, to: node.to }); - return false; - } - }, - }); - - return ranges; -} - -export function findEmojiRanges(state: EditorState): EmojiRange[] { - const document = state.doc.toString(); - const excluded = codeRanges(state); - const ranges: EmojiRange[] = []; - - for (const match of findEmojiShortcodes(document)) { - const { from, to } = match; - const inCode = excluded.some((range) => from < range.to && to > range.from); - const emoji = inCode ? undefined : match.emoji; - const url = emoji ? getEmojiUrl(emoji.shortcode) : undefined; - - if (emoji && url) { - ranges.push({ from, shortcode: emoji.shortcode, to, url }); - } - } - - return ranges; -} - -class EmojiPluginValue { - decorations: DecorationSet; - ranges: EmojiRange[]; - - constructor(view: EditorView) { - this.ranges = findEmojiRanges(view.state); - this.decorations = this.buildDecorations(); - } - - update(update: ViewUpdate) { - if ( - update.docChanged || - syntaxTree(update.startState) !== syntaxTree(update.state) - ) { - this.ranges = findEmojiRanges(update.state); - this.decorations = this.buildDecorations(); - } - } - - private buildDecorations() { - return Decoration.set( - this.ranges.map((range) => - Decoration.replace({ - inclusive: false, - widget: new EmojiWidget(range.shortcode, range.url), - }).range(range.from, range.to), - ), - true, - ); - } -} - -const emojiDecorations = ViewPlugin.fromClass(EmojiPluginValue, { - decorations: (instance) => instance.decorations, - provide: (plugin) => - EditorView.atomicRanges.of( - (view) => view.plugin(plugin)?.decorations ?? Decoration.none, - ), -}); - -function deleteEmoji(view: EditorView, direction: "backward" | "forward") { - const ranges = view.plugin(emojiDecorations)?.ranges ?? []; - const deletions: Array<{ from: number; to: number }> = []; - - for (const selection of view.state.selection.ranges) { - if (selection.empty) { - const emoji = ranges.find((range) => - direction === "backward" - ? selection.from > range.from && selection.from <= range.to - : selection.from >= range.from && selection.from < range.to, - ); - if (emoji) deletions.push({ from: emoji.from, to: emoji.to }); - continue; - } - - let from = selection.from; - let to = selection.to; - let changed = false; - - for (const emoji of ranges) { - if (from < emoji.to && to > emoji.from) { - from = Math.min(from, emoji.from); - to = Math.max(to, emoji.to); - changed = true; - } - } - - if (changed) deletions.push({ from, to }); - } - - if (deletions.length === 0) return false; - - const merged = deletions - .sort((a, b) => a.from - b.from) - .reduce>((result, deletion) => { - const previous = result.at(-1); - if (previous && deletion.from <= previous.to) { - previous.to = Math.max(previous.to, deletion.to); - } else { - result.push({ ...deletion }); - } - return result; - }, []); - - view.dispatch({ - changes: merged.map((range) => ({ from: range.from, to: range.to })), - selection: EditorSelection.cursor(merged[0].from), - scrollIntoView: true, - userEvent: direction === "backward" ? "delete.backward" : "delete.forward", - }); - return true; -} - -/** - * Builds markdown styling decorations every time the document or cursor selection changes. - * Token delimiters are hidden unless the cursor is currently intersecting that token range. - */ -const markdownDecorations = ViewPlugin.fromClass( - class { - decorations: DecorationSet; - - constructor(view: EditorView) { - this.decorations = buildDecorations(view); - } - - update(update: ViewUpdate) { - if (update.docChanged || update.selectionSet || update.viewportChanged) { - this.decorations = buildDecorations(update.view); - } - } - }, - { - decorations: (instance: { decorations: DecorationSet }) => - instance.decorations, - }, -); - -/** - * Executes Input. - * @param props Parameter props. - * @returns unknown. - */ -export default function Input(props: InputProps) { - ensureMarkdownStyles(); - - const shellClassName = props.styled - ? "min-h-8 w-full min-w-0 rounded-lg border border-input bg-transparent text-base transition-colors outline-none placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40" - : ""; - - const elementRef = useRef(null); - const viewRef = useRef(undefined); - const setValueRef = useRef(props.setValue); - const onSubmitRef = useRef(props.onSubmit); - const onEmojiSelectRef = useRef( - props.onEmojiSelect, - ); - const invertEnterBehaviorRef = useRef(Boolean(props.invertEnterBehavior)); - const completionCompartmentRef = useRef(null); - completionCompartmentRef.current ??= new Compartment(); - const completionCompartment = completionCompartmentRef.current; - - useEffect(() => { - setValueRef.current = props.setValue; - onSubmitRef.current = props.onSubmit; - onEmojiSelectRef.current = props.onEmojiSelect; - invertEnterBehaviorRef.current = Boolean(props.invertEnterBehavior); - }, [ - props.onEmojiSelect, - props.onSubmit, - props.invertEnterBehavior, - props.setValue, - ]); - - useEffect(() => { - if (!elementRef.current) return; - - const state = EditorState.create({ - doc: props.value, - extensions: createEditorExtensions( - (value) => { - setValueRef.current(value); - }, - () => props.placeholder, - () => invertEnterBehaviorRef.current, - () => onSubmitRef.current?.(), - completionCompartment, - props.emojiFrequencies, - (shortcode) => onEmojiSelectRef.current?.(shortcode), - ), - }); - - viewRef.current = new EditorView({ - state, - parent: elementRef.current, - }); - props.onControllerChange?.({ - focus: () => viewRef.current?.contentDOM.focus({ preventScroll: true }), - hasFocus: () => viewRef.current?.hasFocus ?? false, - insertText: (text) => { - const editor = viewRef.current; - if (!editor) return; - editor.dispatch({ - ...editor.state.replaceSelection(text), - annotations: Transaction.userEvent.of("input.type"), - scrollIntoView: true, - }); - }, - }); - if (props.autoFocus) viewRef.current.focus(); - - return () => { - props.onControllerChange?.(null); - viewRef.current?.destroy(); - viewRef.current = undefined; - }; - // Run once to initialize/destroy the editor instance. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - const editor = viewRef.current; - if (!editor) return; - - const next = props.value; - const current = editor.state.doc.toString(); - - if (next === current) return; - - editor.dispatch({ - changes: { - from: 0, - to: current.length, - insert: next, - }, - annotations: [ - externalValueSync.of(true), - Transaction.addToHistory.of(false), - ], - filter: false, - }); - }, [props.value]); - - useEffect(() => { - const editor = viewRef.current; - const compartment = completionCompartmentRef.current; - if (!editor || !compartment) return; - - const wasActive = completionStatus(editor.state) === "active"; - editor.dispatch({ - effects: compartment.reconfigure( - createEmojiAutocomplete(props.emojiFrequencies, (shortcode) => - onEmojiSelectRef.current?.(shortcode), - ), - ), - }); - if (wasActive) startCompletion(editor); - }, [props.emojiFrequencies]); - - return ( -
- ); -} - -/** - * Executes createEditorExtensions. - * @param onChange Parameter onChange. - * @param getPlaceholder Parameter getPlaceholder. - * @param getInvertEnterBehavior Parameter getInvertEnterBehavior. - * @param onSubmit Parameter onSubmit. - * @returns Extension[]. - */ -function createEditorExtensions( - onChange: (value: string) => void, - getPlaceholder: () => string | undefined, - getInvertEnterBehavior: () => boolean, - onSubmit: () => void, - completionCompartment: Compartment, - emojiFrequencies: Readonly> | undefined, - onEmojiSelect: (shortcode: string) => void, -): Extension[] { - const editorKeymap = [ - ...defaultKeymap, - ...historyKeymap, - indentWithTab, - ] as unknown as readonly KeyBinding[]; - - const customEnterKeymap = keymap.of([ - { - key: "Shift-Enter", - run: (view) => { - if (completionStatus(view.state) === "active") { - return acceptCompletion(view); - } - if (!getInvertEnterBehavior()) { - return false; - } - - onSubmit(); - return true; - }, - }, - { - key: "Enter", - run: (view) => { - if (completionStatus(view.state) === "active") { - return acceptCompletion(view); - } - if (getInvertEnterBehavior()) { - return false; - } - - onSubmit(); - return true; - }, - }, - ]); - const completionTabKeymap = keymap.of([ - { - key: "Tab", - run: (view) => - completionStatus(view.state) === "active" - ? acceptCompletion(view) - : false, - }, - ]); - const emojiDeletionKeymap = keymap.of([ - { - key: "Backspace", - run: (view) => deleteEmoji(view, "backward"), - }, - { - key: "Delete", - run: (view) => deleteEmoji(view, "forward"), - }, - ]); - - return [ - history(), - markdown(), - completionCompartment.of( - createEmojiAutocomplete(emojiFrequencies, onEmojiSelect), - ), - emojiDecorations, - keymap.of(editorKeymap), - Prec.highest(completionTabKeymap), - Prec.highest(emojiDeletionKeymap), - Prec.highest(customEnterKeymap), - EditorView.lineWrapping, - placeholder(getPlaceholder() ?? ""), - EditorView.updateListener.of((update: ViewUpdate) => { - if (!update.docChanged) return; - if ( - update.transactions.some( - (transaction) => transaction.annotation(externalValueSync) === true, - ) - ) { - return; - } - onChange(update.state.doc.toString()); - }), - EditorView.theme({ - "&": { - fontSize: "inherit", - }, - "&.cm-editor": { - width: "100%", - }, - }), - EditorView.editorAttributes.of({ - class: "tm-md-editor", - spellcheck: "true", - "aria-label": "Markdown input", - }), - markdownDecorations, - ]; -} - -function createEmojiAutocomplete( - frequencies: Readonly> | undefined, - onEmojiSelect: (shortcode: string) => void, -) { - return autocompletion({ - activateOnTyping: true, - addToOptions: [ - { - position: 20, - render(completion) { - const container = document.createElement("span"); - createRoot(container).render( - , - ); - return container; - }, - }, - ], - maxRenderedOptions: MAX_RENDERED_EMOJI_OPTIONS, - override: [createEmojiCompletionSource(frequencies, onEmojiSelect)], - }); -} - -function normalizedFrequencies( - frequencies: Readonly> | undefined, -) { - const normalized = new Map(); - for (const [value, frequency] of Object.entries(frequencies ?? {})) { - const shortcode = resolveEmoji(value)?.shortcode; - if (!shortcode || !Number.isFinite(frequency) || frequency <= 0) continue; - normalized.set(shortcode, (normalized.get(shortcode) ?? 0) + frequency); - } - return normalized; -} - -export function createEmojiCompletionSource( - frequencies?: Readonly>, - onEmojiSelect: (shortcode: string) => void = () => undefined, -) { - const normalized = normalizedFrequencies(frequencies); - const maxFrequency = Math.max(0, ...normalized.values()); - - return (context: CompletionContext): CompletionResult | null => { - const token = context.matchBefore(/:[a-z0-9_+-]*$/i); - if (!token) return null; - if ( - codeRanges(context.state).some( - (range) => token.from < range.to && token.to > range.from, - ) - ) { - return null; - } - - const characterBefore = context.state.sliceDoc( - Math.max(0, token.from - 1), - token.from, - ); - if (characterBefore && /[a-z0-9_]/i.test(characterBefore)) return null; - - const query = token.text.slice(1).toLowerCase(); - const options: Completion[] = searchEmojis(query) - .map((emoji) => { - const aliases = emoji.aliases.map((alias) => alias.toLowerCase()); - const matchedAlias = - aliases.find((alias) => alias === query) ?? - aliases.find((alias) => alias.startsWith(query)) ?? - aliases.find((alias) => alias.includes(query)) ?? - emoji.name; - const relevance = !query - ? 0 - : matchedAlias === query - ? 80 - : matchedAlias.startsWith(query) - ? 40 - : 0; - const frequency = normalized.get(emoji.shortcode) ?? 0; - const usage = - maxFrequency > 0 - ? (15 * Math.log1p(frequency)) / Math.log1p(maxFrequency) - : 0; - - return { - apply(view, completion, from, to) { - view.dispatch({ - annotations: pickedCompletion.of(completion), - changes: { from, insert: `${emoji.shortcode} `, to }, - selection: EditorSelection.cursor( - from + emoji.shortcode.length + 1, - ), - }); - onEmojiSelect(emoji.shortcode); - }, - boost: relevance + usage, - displayLabel: emoji.shortcode, - label: `:${matchedAlias}:`, - type: "text", - frequency, - relevance, - } satisfies Completion & { frequency: number; relevance: number }; - }) - .sort( - (a, b) => - b.relevance - a.relevance || - b.frequency - a.frequency || - (a.displayLabel ?? a.label).localeCompare(b.displayLabel ?? b.label), - ); - - return { - from: token.from, - options, - validFor: /^:[a-z0-9_+-]*$/i, - }; - }; -} - -export const emojiCompletionSource = createEmojiCompletionSource(); - -/** - * Executes buildDecorations. - * @param view Parameter view. - * @returns DecorationSet. - */ -function buildDecorations(view: EditorView): DecorationSet { - const builder: Range[] = []; - const selections = view.state.selection.ranges.map( - (range: SelectionRange) => ({ - from: range.from, - to: range.to, - }), - ); - - let codeFenceOpen = false; - - for ( - let lineNumber = 1; - lineNumber <= view.state.doc.lines; - lineNumber += 1 - ) { - const line = view.state.doc.line(lineNumber); - const text = line.text; - const lineFrom = line.from; - const trimmed = text.trim(); - - const fence = text.match(/^```\s*([^`]*)$/); - if (fence) { - const ticksStart = lineFrom + text.indexOf("```"); - const ticksEnd = ticksStart + 3; - addHiddenToken(builder, selections, { from: ticksStart, to: ticksEnd }); - if (trimmed.length > 3) { - addHiddenToken(builder, selections, { - from: ticksEnd, - to: line.to, - }); - } - codeFenceOpen = !codeFenceOpen; - continue; - } - - if (codeFenceOpen) { - builder.push(codeLineDecoration.range(lineFrom)); - continue; - } - - const heading = text.match(/^(#{1,6})\s+/); - if (heading) { - const markerLength = heading[0].length; - addHiddenToken(builder, selections, { - from: lineFrom, - to: lineFrom + markerLength, - }); - - const level = heading[1].length; - const headingClass = Decoration.mark({ - class: `tm-md-heading tm-md-h${String(level)}`, - }); - const contentFrom = lineFrom + markerLength; - if (contentFrom < line.to) { - builder.push(headingClass.range(contentFrom, line.to)); - } - } - - const quote = text.match(/^>\s?/); - if (quote) { - addHiddenToken(builder, selections, { - from: lineFrom, - to: lineFrom + quote[0].length, - }); - } - - const unordered = text.match(/^(\s*)([-+*])\s+(?:\[( |x|X)\]\s+)?/); - if (unordered) { - const markerStart = lineFrom + unordered[1].length; - const markerEnd = markerStart + unordered[2].length + 1; - addHiddenToken(builder, selections, { from: markerStart, to: markerEnd }); - - const checkbox = unordered[0].match(/\[( |x|X)\]\s+$/); - if (checkbox) { - const checkboxStart = lineFrom + unordered[0].lastIndexOf("["); - addHiddenToken(builder, selections, { - from: checkboxStart, - to: checkboxStart + checkbox[0].length, - }); - } - } - - const ordered = text.match(/^(\s*)(\d+\.)\s+/); - if (ordered) { - const markerStart = lineFrom + ordered[1].length; - addHiddenToken(builder, selections, { - from: markerStart, - to: markerStart + ordered[2].length + 1, - }); - } - - if (/^(?:\*\s*){3,}$|^(?:-\s*){3,}$|^(?:_\s*){3,}$/.test(trimmed)) { - if (lineFrom < line.to) { - builder.push( - Decoration.mark({ class: "tm-md-hr" }).range(lineFrom, line.to), - ); - } - continue; - } - - const tableSeparator = /^\|?\s*:?-{3,}:?\s*(?:\|\s*:?-{3,}:?\s*)+\|?$/.test( - text, - ); - if (tableSeparator) { - if (lineFrom < line.to) { - builder.push( - Decoration.mark({ class: "tm-md-del" }).range(lineFrom, line.to), - ); - } - continue; - } - - const { styleRanges, tokenRanges } = collectInlineRanges(text, lineFrom); - - for (const range of styleRanges) { - if (range.from >= range.to) continue; - - if (range.className === "tm-md-strong") { - builder.push(strongDecoration.range(range.from, range.to)); - } else if (range.className === "tm-md-em") { - builder.push(emDecoration.range(range.from, range.to)); - } else if (range.className === "tm-md-del") { - builder.push(delDecoration.range(range.from, range.to)); - } else if (range.className === "tm-md-code") { - builder.push(codeDecoration.range(range.from, range.to)); - } else if (range.className === "tm-md-link") { - builder.push(linkDecoration.range(range.from, range.to)); - } - } - - for (const token of tokenRanges) { - addHiddenToken(builder, selections, token); - } - } - - return Decoration.set(builder, true); -} - -/** - * Keeps markdown syntax visible only when user selection intersects the token. - * This preserves cursor predictability and cross-token selection while still hiding syntax during reading. - */ -function addHiddenToken( - builder: Range[], - selections: ReadonlyArray<{ from: number; to: number }>, - token: { - from: number; - to: number; - }, -): void { - if (token.from >= token.to) return; - - const overlapsSelection = selections.some((selection) => { - const selectionFrom = Math.min(selection.from, selection.to); - const selectionTo = Math.max(selection.from, selection.to); - - if (selectionFrom === selectionTo) { - return selectionFrom >= token.from && selectionFrom <= token.to; - } - - return selectionFrom < token.to && selectionTo > token.from; - }); - - if (overlapsSelection) return; - builder.push(hiddenTokenDecoration.range(token.from, token.to)); -} diff --git a/packages/markdown/src/markdown.tsx b/packages/markdown/src/markdown.tsx deleted file mode 100644 index cd2a210..0000000 --- a/packages/markdown/src/markdown.tsx +++ /dev/null @@ -1,815 +0,0 @@ -import { - Fragment, - useEffect, - useRef, - useState, - type ReactElement, - type ReactNode, -} from "react"; -import Emoji from "./emoji"; -import { findEmojiShortcodes } from "./emojiData"; -import { Check } from "lucide-react"; - -type InlineNode = - | { type: "text"; value: string } - | { type: "emoji"; shortcode: string } - | { type: "strong"; value: string } - | { type: "em"; value: string } - | { type: "del"; value: string } - | { type: "code"; value: string } - | { type: "link"; label: string; href: string } - | { type: "image"; alt: string; src: string }; - -type InlineDecorationRange = { - from: number; - to: number; - className: string; -}; - -type InlineTokenRange = { - from: number; - to: number; -}; - -type ListItem = { - text: string; - checked: boolean | null; -}; - -type TableBlock = { - type: "table"; - headers: string[]; - rows: string[][]; -}; - -type MarkdownBlock = - | { - type: "paragraph"; - text: string; - } - | { - type: "heading"; - level: number; - text: string; - } - | { - type: "hr"; - } - | { - type: "blockquote"; - text: string; - } - | { - type: "code"; - language: string; - code: string; - } - | { - type: "list"; - ordered: boolean; - items: ListItem[]; - } - | TableBlock; - -const INLINE_TOKEN_REGEX = - /!\[([^\]]*)\]\(([^)\s]+(?:\s+"[^"]*")?)\)|\[([^\]]+)\]\(([^)\s]+(?:\s+"[^"]*")?)\)|`([^`\n]+)`|~~([^~\n]+)~~|\*\*([^*\n]+)\*\*|__([^_\n]+)__|\*([^*\n]+)\*|(? - - - ); -} - -function CopyableCode({ - block = false, - language, - value, -}: { - block?: boolean; - language?: string; - value: string; -}) { - const [copied, setCopied] = useState(false); - const copiedTimer = useRef | undefined>( - undefined, - ); - - useEffect( - () => () => { - clearTimeout(copiedTimer.current); - }, - [], - ); - - async function copy() { - await navigator.clipboard.writeText(value); - setCopied(true); - clearTimeout(copiedTimer.current); - copiedTimer.current = setTimeout(() => setCopied(false), 1200); - } - - const code = ( - void copy()} - onKeyDown={(event) => { - if (event.key !== "Enter" && event.key !== " ") return; - event.preventDefault(); - void copy(); - }} - > - {value} - - ); - - if (block) { - return ( -
-
{code}
- -
- ); - } - - return ( - <> - {code} - - - ); -} - -/** - * Executes parseInlineNodes. - * @param input Parameter input. - * @returns InlineNode[]. - */ -export function parseInlineNodes(input: string): InlineNode[] { - const nodes: InlineNode[] = []; - - let cursor = 0; - let match = INLINE_TOKEN_REGEX.exec(input); - - while (match) { - const index = match.index; - const raw = match[0]; - - if (index > cursor) { - nodes.push(...parseEmojiText(input.slice(cursor, index))); - } - - if (match[1] !== undefined && match[2] !== undefined) { - nodes.push({ type: "image", alt: match[1], src: normalizeUrl(match[2]) }); - } else if (match[3] !== undefined && match[4] !== undefined) { - nodes.push({ - type: "link", - label: match[3], - href: normalizeUrl(match[4]), - }); - } else if (match[5] !== undefined) { - nodes.push({ type: "code", value: match[5] }); - } else if (match[6] !== undefined) { - nodes.push({ type: "del", value: match[6] }); - } else if (match[7] !== undefined || match[8] !== undefined) { - nodes.push({ type: "strong", value: match[7] ?? match[8] ?? "" }); - } else if (match[9] !== undefined || match[10] !== undefined) { - nodes.push({ type: "em", value: match[9] ?? match[10] ?? "" }); - } else { - nodes.push(...parseEmojiText(raw)); - } - - cursor = index + raw.length; - match = INLINE_TOKEN_REGEX.exec(input); - } - - if (cursor < input.length) { - nodes.push(...parseEmojiText(input.slice(cursor))); - } - - INLINE_TOKEN_REGEX.lastIndex = 0; - return nodes; -} - -export function parseEmojiText(input: string): InlineNode[] { - const nodes: InlineNode[] = []; - let cursor = 0; - - for (const match of findEmojiShortcodes(input)) { - if (match.from > cursor) { - nodes.push({ type: "text", value: input.slice(cursor, match.from) }); - } - - nodes.push({ type: "emoji", shortcode: match.emoji.shortcode }); - cursor = match.to; - } - - if (cursor < input.length) { - nodes.push({ type: "text", value: input.slice(cursor) }); - } - - return nodes; -} - -/** - * Executes collectInlineRanges. - * @param input Parameter input. - * @param offset Parameter offset. - * @returns { - styleRanges: InlineDecorationRange[]; - tokenRanges: InlineTokenRange[]; -}. - */ -export function collectInlineRanges( - input: string, - offset = 0, -): { - styleRanges: InlineDecorationRange[]; - tokenRanges: InlineTokenRange[]; -} { - const styleRanges: InlineDecorationRange[] = []; - const tokenRanges: InlineTokenRange[] = []; - - let match = INLINE_TOKEN_REGEX.exec(input); - - while (match) { - const raw = match[0]; - const start = offset + match.index; - const end = start + raw.length; - - if (match[1] !== undefined && match[2] !== undefined) { - const openLength = 2; - const closeLength = raw.endsWith(")") ? 1 : 0; - - const imageEnd = start + openLength + match[1].length; - tokenRanges.push({ from: start, to: start + openLength }); - tokenRanges.push({ from: imageEnd, to: imageEnd + 1 }); - - const srcStart = imageEnd + 1; - const srcEnd = end - closeLength; - tokenRanges.push({ from: srcStart, to: srcStart + 1 }); - tokenRanges.push({ from: srcEnd, to: srcEnd + closeLength }); - } else if (match[3] !== undefined && match[4] !== undefined) { - const label = match[3]; - const labelStart = start + 1; - const labelEnd = labelStart + label.length; - - tokenRanges.push({ from: start, to: start + 1 }); - tokenRanges.push({ from: labelEnd, to: labelEnd + 1 }); - tokenRanges.push({ from: labelEnd + 1, to: labelEnd + 2 }); - tokenRanges.push({ from: end - 1, to: end }); - - styleRanges.push({ - from: labelStart, - to: labelEnd, - className: "tm-md-link", - }); - } else if (match[5] !== undefined) { - const codeStart = start + 1; - const codeEnd = end - 1; - - tokenRanges.push({ from: start, to: start + 1 }); - tokenRanges.push({ from: end - 1, to: end }); - styleRanges.push({ - from: codeStart, - to: codeEnd, - className: "tm-md-code", - }); - } else if (match[6] !== undefined) { - const contentStart = start + 2; - const contentEnd = end - 2; - - tokenRanges.push({ from: start, to: start + 2 }); - tokenRanges.push({ from: end - 2, to: end }); - styleRanges.push({ - from: contentStart, - to: contentEnd, - className: "tm-md-del", - }); - } else if (match[7] !== undefined || match[8] !== undefined) { - const contentStart = start + 2; - const contentEnd = end - 2; - - tokenRanges.push({ from: start, to: start + 2 }); - tokenRanges.push({ from: end - 2, to: end }); - styleRanges.push({ - from: contentStart, - to: contentEnd, - className: "tm-md-strong", - }); - } else if (match[9] !== undefined || match[10] !== undefined) { - const contentStart = start + 1; - const contentEnd = end - 1; - - tokenRanges.push({ from: start, to: start + 1 }); - tokenRanges.push({ from: end - 1, to: end }); - styleRanges.push({ - from: contentStart, - to: contentEnd, - className: "tm-md-em", - }); - } - - match = INLINE_TOKEN_REGEX.exec(input); - } - - INLINE_TOKEN_REGEX.lastIndex = 0; - return { styleRanges, tokenRanges }; -} - -/** - * Executes parseMarkdownBlocks. - * @param markdown Parameter markdown. - * @returns MarkdownBlock[]. - */ -export function parseMarkdownBlocks(markdown: string): MarkdownBlock[] { - const lines = markdown.replace(/\r\n/g, "\n").split("\n"); - const blocks: MarkdownBlock[] = []; - - let index = 0; - - while (index < lines.length) { - const line = lines[index]; - - if (!line.trim()) { - index += 1; - continue; - } - - const codeFence = line.match(/^```\s*([^`]*)$/); - if (codeFence) { - const language = (codeFence[1] ?? "").trim(); - const codeLines: string[] = []; - index += 1; - - while (index < lines.length && !/^```\s*$/.test(lines[index])) { - codeLines.push(lines[index]); - index += 1; - } - - if (index < lines.length) { - index += 1; - } - - blocks.push({ type: "code", language, code: codeLines.join("\n") }); - continue; - } - - if (/^(?:\*\s*){3,}$|^(?:-\s*){3,}$|^(?:_\s*){3,}$/.test(line.trim())) { - blocks.push({ type: "hr" }); - index += 1; - continue; - } - - const heading = line.match(/^(#{1,6})\s+(.+)$/); - if (heading) { - blocks.push({ - type: "heading", - level: heading[1].length, - text: heading[2], - }); - index += 1; - continue; - } - - const quote = line.match(/^>\s?(.*)$/); - if (quote) { - const quoteLines: string[] = [quote[1]]; - index += 1; - - while (index < lines.length) { - const next = lines[index].match(/^>\s?(.*)$/); - if (!next) break; - quoteLines.push(next[1]); - index += 1; - } - - blocks.push({ type: "blockquote", text: quoteLines.join("\n") }); - continue; - } - - const tableCandidate = readTable(lines, index); - if (tableCandidate) { - blocks.push(tableCandidate.block); - index = tableCandidate.nextIndex; - continue; - } - - const unordered = line.match(/^\s*[-*+]\s+(.*)$/); - const ordered = line.match(/^\s*\d+\.\s+(.*)$/); - if (unordered || ordered) { - const orderedList = Boolean(ordered); - const items: ListItem[] = []; - - while (index < lines.length) { - const current = lines[index]; - const match = orderedList - ? current.match(/^\s*\d+\.\s+(.*)$/) - : current.match(/^\s*[-*+]\s+(.*)$/); - - if (!match) break; - - const task = match[1].match(/^\[( |x|X)\]\s+(.*)$/); - if (task) { - items.push({ - text: task[2], - checked: task[1].toLowerCase() === "x", - }); - } else { - items.push({ text: match[1], checked: null }); - } - - index += 1; - } - - blocks.push({ type: "list", ordered: orderedList, items }); - continue; - } - - const paragraphLines = [line]; - index += 1; - - while ( - index < lines.length && - lines[index].trim() && - !/^(#{1,6})\s+/.test(lines[index]) && - !/^```\s*/.test(lines[index]) && - !/^>\s?/.test(lines[index]) && - !/^\s*[-*+]\s+/.test(lines[index]) && - !/^\s*\d+\.\s+/.test(lines[index]) && - !/^(?:\*\s*){3,}$|^(?:-\s*){3,}$|^(?:_\s*){3,}$/.test(lines[index].trim()) - ) { - paragraphLines.push(lines[index]); - index += 1; - } - - blocks.push({ type: "paragraph", text: paragraphLines.join("\n") }); - } - - return blocks; -} - -/** - * Executes renderInline. - * @param nodes Parameter nodes. - * @returns React.ReactNode[]. - */ -function renderInline(nodes: InlineNode[]): ReactNode[] { - return nodes.map((node, index) => { - if (node.type === "text") { - return node.value; - } - - if (node.type === "emoji") { - return ( - - ); - } - - if (node.type === "strong") { - return ( - - {renderInline(parseEmojiText(node.value))} - - ); - } - - if (node.type === "em") { - return ( - - {renderInline(parseEmojiText(node.value))} - - ); - } - - if (node.type === "del") { - return ( - - {renderInline(parseEmojiText(node.value))} - - ); - } - - if (node.type === "code") { - return ; - } - - if (node.type === "link") { - return ( - - {renderInline(parseEmojiText(node.label))} - - ); - } - - return ( - {node.alt} - ); - }); -} - -/** - * Executes renderBlocks. - * @param blocks Parameter blocks. - * @returns React.ReactElement. - */ -export function renderBlocks(blocks: MarkdownBlock[]): ReactElement { - return ( - <> - {blocks.map((block, blockIndex) => { - if (block.type === "heading") { - const className = `tm-md-heading tm-md-h${String(block.level)}`; - if (block.level === 1) - return ( -

- {renderInline(parseInlineNodes(block.text))} -

- ); - if (block.level === 2) - return ( -

- {renderInline(parseInlineNodes(block.text))} -

- ); - if (block.level === 3) - return ( -

- {renderInline(parseInlineNodes(block.text))} -

- ); - if (block.level === 4) - return ( -

- {renderInline(parseInlineNodes(block.text))} -

- ); - if (block.level === 5) - return ( -
- {renderInline(parseInlineNodes(block.text))} -
- ); - return ( -
- {renderInline(parseInlineNodes(block.text))} -
- ); - } - - if (block.type === "blockquote") { - return ( -
- {block.text.split("\n").map((line, lineIndex) => ( -

{renderInline(parseInlineNodes(line))}

- ))} -
- ); - } - - if (block.type === "code") { - return ( - - ); - } - - if (block.type === "list") { - const Tag = block.ordered ? "ol" : "ul"; - return ( - - {block.items.map((item, itemIndex) => ( -
  • - {item.checked !== null ? ( - - ) : null} - {renderInline(parseInlineNodes(item.text))} -
  • - ))} -
    - ); - } - - if (block.type === "table") { - return ( -
    - - - - {block.headers.map((header, headerIndex) => ( - - ))} - - - - {block.rows.map((row, rowIndex) => ( - - {row.map((cell, cellIndex) => ( - - ))} - - ))} - -
    - {renderInline(parseInlineNodes(header))} -
    - {renderInline(parseInlineNodes(cell))} -
    -
    - ); - } - - if (block.type === "hr") { - return
    ; - } - - return ( -

    - {block.text.split("\n").map((line, lineIndex) => ( - - {lineIndex > 0 ?
    : null} - {renderInline(parseInlineNodes(line))} -
    - ))} -

    - ); - })} - - ); -} - -/** - * Executes normalizeUrl. - * @param input Parameter input. - * @returns string. - */ -function normalizeUrl(input: string): string { - const value = input.trim(); - if (/^(https?:|mailto:|tel:|\/)/i.test(value)) { - return value; - } - - return "#"; -} - -/** - * Executes splitTableRow. - * @param row Parameter row. - * @returns string[]. - */ -function splitTableRow(row: string): string[] { - const cleaned = row.trim().replace(/^\|/, "").replace(/\|$/, ""); - return cleaned.split("|").map((cell) => cell.trim()); -} - -/** - * Executes readTable. - * @param lines Parameter lines. - * @param index Parameter index. - * @returns { block: TableBlock; nextIndex: number } | null. - */ -function readTable( - lines: string[], - index: number, -): { block: TableBlock; nextIndex: number } | null { - const header = lines[index] ?? ""; - const separator = lines[index + 1] ?? ""; - - if (!header.includes("|") || !separator.includes("|")) { - return null; - } - - const separatorCells = splitTableRow(separator); - const isSeparator = separatorCells.every((cell) => /^:?-{3,}:?$/.test(cell)); - if (!isSeparator) { - return null; - } - - const headers = splitTableRow(header); - const rows: string[][] = []; - let cursor = index + 2; - - while (cursor < lines.length && lines[cursor].includes("|")) { - rows.push(splitTableRow(lines[cursor])); - cursor += 1; - } - - return { - block: { type: "table", headers, rows }, - nextIndex: cursor, - }; -} - -const markdownStyles = ` -.tm-md-root { color: var(--foreground); line-height: 1.65; font-size: 1rem; } -.tm-md-heading { margin: 0.2rem 0 0.35rem; font-weight: 700; line-height: 1.25; } -.tm-md-h1 { font-size: 1.65rem; } -.tm-md-h2 { font-size: 1.45rem; } -.tm-md-h3 { font-size: 1.25rem; } -.tm-md-h4 { font-size: 1.1rem; } -.tm-md-h5 { font-size: 1rem; } -.tm-md-h6 { font-size: 0.95rem; opacity: 0.9; } -.tm-md-blockquote { margin: 0.45rem 0; padding-left: 0.75rem; opacity: 0.95; } -.tm-md-blockquote p { margin: 0.2rem 0; } -.tm-md-pre { margin: 0.45rem 0; padding: 0.65rem 0.75rem; border-radius: 0.5rem; background: var(--muted); overflow-x: auto; } -.tm-md-code, .tm-md-codeblock { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 0.87em; cursor: pointer; } -.tm-md-code { padding: 0.08rem 0.32rem; border: 1px solid var(--border); border-radius: 0.28rem; background: var(--muted); } -.tm-md-codeblock { display: block; } -.tm-md-code:focus-visible, .tm-md-codeblock:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; } -.tm-md-strong { font-weight: 700; } -.tm-md-em { font-style: italic; } -.tm-md-del { text-decoration: line-through; } -.tm-md-link { color: var(--primary); text-decoration: underline; text-underline-offset: 0.14rem; } -.tm-md-image { display: block; max-width: 100%; border-radius: 0.4rem; margin: 0.5rem 0; } -.tm-md-emoji { display: inline-block; width: 1.15em; height: 1.15em; vertical-align: -0.18em; } -.tm-md-ul, .tm-md-ol { margin: 0.3rem 0 0.35rem 1.2rem; padding: 0; } -.tm-md-li { margin: 0.2rem 0; } -.tm-md-checkbox { margin-right: 0.5rem; vertical-align: middle; } -.tm-md-table-wrap { overflow-x: auto; margin: 0.45rem 0; } -.tm-md-table { border-collapse: collapse; width: 100%; min-width: 16rem; } -.tm-md-table th, .tm-md-table td { padding: 0.4rem 0.5rem; text-align: left; } -.tm-md-table th { background: var(--muted); font-weight: 600; } -.tm-md-hr { margin: 0.55rem 0; } - -.cm-editor.tm-md-editor { border-radius: inherit; background: transparent; caret-color: var(--foreground); } -.cm-editor.tm-md-editor.cm-focused { outline: none; box-shadow: none; } -.cm-editor.tm-md-editor .cm-scroller { font-family: inherit; line-height: 1.55; max-height: 30vh; overflow-y: auto; overflow-x: hidden; } -.cm-editor.tm-md-editor .cm-content { caret-color: var(--foreground); } -.cm-editor.tm-md-editor .cm-content { padding: var(--tm-md-content-padding, 0.25rem 0.625rem); min-height: 2rem; } -.cm-editor.tm-md-editor .cm-line { padding: 0; color: var(--foreground); } -.cm-editor.tm-md-editor .tm-md-editor-emoji { display: inline-block; width: 1.15em; height: 1.15em; vertical-align: -0.18em; object-fit: contain; pointer-events: none; } -.cm-editor.tm-md-editor .tm-md-hidden-token { color: transparent; opacity: 0; font-size: inherit; } -.cm-editor.tm-md-editor .tm-md-code-line { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; background: var(--muted); border-radius: 0.3rem; } -.cm-tooltip.cm-tooltip-autocomplete { min-width: 18rem; max-width: min(26rem, calc(100vw - 1rem)); overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius); background: var(--popover); color: var(--popover-foreground); box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); font-family: "Public Sans Variable", sans-serif; font-size: 0.875rem; } -.cm-editor.tm-md-editor .cm-tooltip.cm-tooltip-autocomplete > ul { max-height: min(20rem, 45vh); padding: 0.25rem; font-family: "Public Sans Variable", sans-serif; scrollbar-width: thin; scrollbar-color: var(--border) transparent; } -.cm-tooltip.cm-tooltip-autocomplete > ul::-webkit-scrollbar { width: 6px; height: 6px; } -.cm-tooltip.cm-tooltip-autocomplete > ul::-webkit-scrollbar-track { background: transparent; } -.cm-tooltip.cm-tooltip-autocomplete > ul::-webkit-scrollbar-thumb { border-radius: 9999px; background: var(--border); } -.cm-tooltip.cm-tooltip-autocomplete > ul > li { display: flex; min-height: 2.25rem; align-items: center; border-radius: calc(var(--radius) * 0.8); padding: 0.3rem 0.5rem; color: var(--popover-foreground); } -.cm-tooltip.cm-tooltip-autocomplete > ul > li:hover, -.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] { background: var(--accent); color: var(--accent-foreground); } -.cm-tooltip.cm-tooltip-autocomplete .cm-completionIcon { display: none; } -.cm-tooltip.cm-tooltip-autocomplete .cm-completionLabel { overflow: hidden; text-overflow: ellipsis; } -.cm-tooltip.cm-tooltip-autocomplete .cm-completionMatchedText { color: inherit; text-decoration: none; font-weight: 600; } -.cm-tooltip-autocomplete .tm-md-completion-emoji { display: inline-block; width: 1.35rem; height: 1.35rem; flex: 0 0 auto; margin-right: 0.5rem; vertical-align: middle; } -`; - -/** - * Executes ensureMarkdownStyles. - * @param none This function has no parameters. - * @returns void. - */ -export function ensureMarkdownStyles(): void { - if (typeof document === "undefined") return; - - const styleId = "tensamin-markdown-styles"; - let style = document.getElementById(styleId) as HTMLStyleElement | null; - - if (!style) { - style = document.createElement("style"); - style.id = styleId; - document.head.appendChild(style); - } - - if (style.textContent !== markdownStyles) { - style.textContent = markdownStyles; - } -} diff --git a/packages/markdown/src/text.tsx b/packages/markdown/src/text.tsx deleted file mode 100644 index ca65fe0..0000000 --- a/packages/markdown/src/text.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { useMemo, type CSSProperties } from "react"; - -import { - ensureMarkdownStyles, - parseMarkdownBlocks, - renderBlocks, -} from "./markdown"; - -export type TextProps = { - value: string; - fontSize?: CSSProperties["fontSize"]; -}; - -/** - * Executes Text. - * @param props Parameter props. - * @returns unknown. - */ -export default function Text(props: TextProps) { - ensureMarkdownStyles(); - - const blocks = useMemo(() => parseMarkdownBlocks(props.value), [props.value]); - const renderedBlocks = useMemo(() => renderBlocks(blocks), [blocks]); - - return ( -
    - {renderedBlocks} -
    - ); -} diff --git a/packages/markdown/todo.md b/packages/markdown/todo.md deleted file mode 100644 index b59da98..0000000 --- a/packages/markdown/todo.md +++ /dev/null @@ -1 +0,0 @@ -- Improve the Input box diff --git a/packages/markdown/tsconfig.json b/packages/markdown/tsconfig.json deleted file mode 100644 index 9714625..0000000 --- a/packages/markdown/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "bundler", - "jsx": "react-jsx", - "strict": true, - "skipLibCheck": true, - "noEmit": true - }, - "include": ["src"] -} diff --git a/packages/settings/package.json b/packages/settings/package.json index 268974c..f3833a9 100644 --- a/packages/settings/package.json +++ b/packages/settings/package.json @@ -16,7 +16,6 @@ "@tanstack/react-router": "^1.170.21", "@tensamin/cache": "workspace:*", "@tensamin/hotkeys": "workspace:*", - "@tensamin/markdown": "workspace:*", "@tensamin/mtp": "workspace:*", "@tensamin/shared": "workspace:*", "@tensamin/storage": "workspace:*", diff --git a/packages/settings/src/pages/profile.tsx b/packages/settings/src/pages/profile.tsx index 080c343..7f8cd5a 100644 --- a/packages/settings/src/pages/profile.tsx +++ b/packages/settings/src/pages/profile.tsx @@ -1,4 +1,4 @@ -import MDInput from "@tensamin/markdown/input"; +import { Input as MDInput } from "@methanium/ui/markdown"; import { useMTP } from "@tensamin/mtp"; import { mtp } from "@tensamin/shared/data"; import { useStorage } from "@tensamin/storage/context"; @@ -145,7 +145,6 @@ export default function Page() { value={draftUser.Username || ""} /> =20'} + + '@shikijs/engine-javascript@4.4.2': + resolution: {integrity: sha512-MnIkeqWdVPUWsxlx8gKLVCJFTsqrQJgpTPBPpQwaFeJ56lOnJxj5aN2LUFnfxUEcvOQuNocmbaMnVrCEln6rkw==} + engines: {node: '>=20'} + + '@shikijs/engine-oniguruma@4.4.2': + resolution: {integrity: sha512-GLhowz1+jixjz+wiZ3wMnOn1jTxiFCGl2PkXufivbnwPHKuyw1AYqu5/hbWhZZ2oAb0NP05WUJhYeigY14drnw==} + engines: {node: '>=20'} + + '@shikijs/langs@4.4.2': + resolution: {integrity: sha512-8DfeusD+Zdv/eYIDdXyJTUnSMHt+aAWjAOCXV20HNGAHRlInXpG8wh421v6B91WOm9TFwRLN+b/LG5F2NAIojg==} + engines: {node: '>=20'} + + '@shikijs/primitive@4.4.2': + resolution: {integrity: sha512-l6fQQKsOMlz72n38fztmSgZ76MO6KSWuw8o+GJ+FhmqrpC9pIOJNQNXGgbb5yX2AwpzlEHwsaLPnk/8o4Fm+rA==} + engines: {node: '>=20'} + + '@shikijs/themes@4.4.2': + resolution: {integrity: sha512-H0CFoL07ddDC2Dd6EdrPYNkRhUR6YCkJlnuYFceYYUJJA5TIm2b5B33qqiDYryBExgbKMndFJPb2u1gTuqO37g==} + engines: {node: '>=20'} + + '@shikijs/types@4.4.2': + resolution: {integrity: sha512-PFYitV4vpDr/iPCIhnHp+Q4ftic5N5VeNJ3KQ1O8gn3h2ar8qgwMAXF7tq4m1CWaMS60fV4VqF6vfnWH4F7vqQ==} + engines: {node: '>=20'} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -1890,12 +1873,6 @@ packages: '@ts-morph/common@0.27.0': resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} - '@twemoji/api@17.0.3': - resolution: {integrity: sha512-iwERjxY0QgPGVwT6b1OKG0Oa9nIfHhJw+Ij1TapTBMKTvVCU6qdXPXX/XKwxKx5QZIJW5GwELUCtw8wlaIQ2ug==} - - '@twemoji/parser@17.0.2': - resolution: {integrity: sha512-X/P7pHsGOxnrupQYUVetIeuxBGgffFu8CLwoPMMjH9CWmQvlXiCpbTW/BXxMOCWXQojgHdmgdvm6IsCqAQ5nxA==} - '@types/cacheable-request@6.0.3': resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} @@ -1941,21 +1918,33 @@ packages: '@types/esrecurse@4.3.1': resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/fs-extra@9.0.13': resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} + '@types/http-cache-semantics@4.2.0': resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/katex@0.16.8': + resolution: {integrity: sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==} + '@types/keyv@3.1.4': resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -1979,6 +1968,12 @@ packages: '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/use-sync-external-store@0.0.6': resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} @@ -2164,6 +2159,9 @@ packages: cpu: [x64] os: [win32] + '@ungap/structured-clone@1.3.3': + resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==} + '@vitejs/plugin-react@6.0.5': resolution: {integrity: sha512-BOVzne/NL162sMdResB25mUv+vWMF5NoAjNf09TeGlE7ZpszZWSD3winycicLJw72yeVsoCn/2kOhEuCvEShMA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2317,6 +2315,9 @@ packages: aws4@1.13.2: resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2408,6 +2409,9 @@ packages: caniuse-lite@1.0.30001809: resolution: {integrity: sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} @@ -2420,6 +2424,18 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -2477,6 +2493,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -2489,6 +2508,10 @@ packages: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} engines: {node: '>= 6'} + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + commander@9.5.0: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} @@ -2624,6 +2647,9 @@ packages: decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -2685,6 +2711,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -2695,6 +2725,9 @@ packages: detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + diff@8.0.4: resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} engines: {node: '>=0.3.1'} @@ -2802,6 +2835,10 @@ packages: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -2857,6 +2894,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + eslint-plugin-react-hooks@7.1.1: resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} engines: {node: '>=18'} @@ -2906,6 +2947,9 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -2957,6 +3001,9 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fallow-type-aware@3.14.0: resolution: {integrity: sha512-D8+bNELjmoVV2dKpmHplQ1YzuheHltmZKaOVJ//hx7h8vFNyp5H3hcJV8rR26ofBU51z9K5eyA7FpgP3hebjwg==} engines: {node: '>=20'} @@ -3130,6 +3177,9 @@ packages: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -3184,6 +3234,45 @@ packages: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} + hast-util-from-dom@5.0.1: + resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} + + hast-util-from-html-isomorphic@2.0.0: + resolution: {integrity: sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-heading-rank@3.0.0: + resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-to-string@3.0.1: + resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} @@ -3198,6 +3287,12 @@ packages: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} @@ -3255,6 +3350,9 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + input-otp@1.4.2: resolution: {integrity: sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==} peerDependencies: @@ -3273,9 +3371,18 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -3298,6 +3405,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-in-ssh@1.0.0: resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} engines: {node: '>=20'} @@ -3440,12 +3550,17 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - jsonfile@5.0.0: - resolution: {integrity: sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==} - jsonfile@6.2.1: resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + katex@0.16.47: + resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==} + hasBin: true + + katex@0.18.2: + resolution: {integrity: sha512-3snve4y0SXTMequLim1FMiPvLGElySam0blN5xQZBqEY3lOJz1TnuaaiugnBZBqHzlSAGmFTYL7MCQkORuLKCA==} + hasBin: true + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -3646,6 +3761,9 @@ packages: resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} engines: {node: '>= 0.6.0'} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + lowercase-keys@2.0.0: resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} engines: {node: '>=8'} @@ -3665,6 +3783,9 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + matcher@3.0.0: resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} engines: {node: '>=10'} @@ -3673,6 +3794,57 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-math@3.0.0: + resolution: {integrity: sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-newline-to-break@2.0.0: + resolution: {integrity: sha512-MbgeFca0hLYIEx/2zGsszCSEJJ1JSCdiY5xQxRcLDDGa8EPvlLPupJ4DSajbMPAnC0je8jfb9TiUATnxxrHUog==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + media-typer@1.1.1: resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} engines: {node: '>= 0.8'} @@ -3688,6 +3860,93 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-math@3.1.0: + resolution: {integrity: sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -3876,6 +4135,12 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} + oniguruma-parser@0.12.2: + resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} + + oniguruma-to-es@4.3.6: + resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} + open@11.0.0: resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} engines: {node: '>=20'} @@ -3920,6 +4185,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -3928,6 +4196,9 @@ packages: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -4044,6 +4315,9 @@ packages: proper-lockfile@4.1.2: resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -4089,6 +4363,12 @@ packages: react-is@19.2.8: resolution: {integrity: sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==} + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + react-redux@9.3.0: resolution: {integrity: sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==} peerDependencies: @@ -4168,6 +4448,42 @@ packages: redux@5.0.1: resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + rehype-autolink-headings@7.1.0: + resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==} + + rehype-katex@7.0.1: + resolution: {integrity: sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==} + + rehype-slug@6.0.0: + resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==} + + remark-breaks@4.0.0: + resolution: {integrity: sha512-IjEjJOkH4FuJvHZVIW0QCDWxcG96kCq7An/KVH2NfJe6rKZU2AsHeB3OEjPNRxi4QC34Xdx7I2KGYn6IpT7gxQ==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-math@6.0.0: + resolution: {integrity: sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4315,6 +4631,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shiki@4.4.2: + resolution: {integrity: sha512-P8F/dFhRevaw2uSdeIYlq/5SXZNY85DPtmXQ947gD1Zj2JqO5AkNvVVBar0Me9JkFx3uzVud/qOtP5ek9NEQGA==} + engines: {node: '>=20'} + side-channel-list@1.0.1: resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} engines: {node: '>= 0.4'} @@ -4365,6 +4685,9 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} @@ -4397,6 +4720,9 @@ packages: string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + stringify-object@5.0.0: resolution: {integrity: sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==} engines: {node: '>=14.16'} @@ -4424,6 +4750,12 @@ packages: style-mod@4.1.3: resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + sumchecker@3.0.1: resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} engines: {node: '>= 8.0'} @@ -4500,6 +4832,12 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + truncate-utf8-bytes@1.0.2: resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} @@ -4572,6 +4910,30 @@ packages: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -4647,6 +5009,15 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} @@ -4737,6 +5108,9 @@ packages: w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + webcrypto-core@1.9.2: resolution: {integrity: sha512-gsXecm82UQNlTBURJGuqOWy1Ww08S3kZUcr3aOJS02Pk0xLtkfeUAVC0u0xhgdonFme80edSJUIJyuvL/7250Q==} @@ -4862,6 +5236,9 @@ packages: use-sync-external-store: optional: true + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: '@babel/code-frame@7.29.7': @@ -5549,25 +5926,44 @@ snapshots: '@marijn/find-cluster-break@1.0.3': {} - '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3)': + '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.28/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@base-ui/react': 1.7.0(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@codemirror/autocomplete': 6.20.3 + '@codemirror/commands': 6.10.4 + '@codemirror/lang-markdown': 6.5.2 + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.8 + '@shikijs/langs': 4.4.2 '@tauri-apps/api': 2.11.1 class-variance-authority: 0.7.1 clsx: 2.1.1 cmdk: 1.1.1(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) embla-carousel-react: 8.6.0(react@19.2.8) + emojibase-data: 17.0.0(emojibase@17.0.0) + hast-util-to-jsx-runtime: 2.3.6(supports-color@7.2.0) input-otp: 1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + katex: 0.18.2 lucide-react: 1.30.0(react@19.2.8) next-themes: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) + react-markdown: 10.1.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) react-resizable-panels: 4.12.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) recharts: 3.10.1(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1) + rehype-autolink-headings: 7.1.0 + rehype-katex: 7.0.1 + rehype-slug: 6.0.0 + remark-breaks: 4.0.0 + remark-gfm: 4.0.1(supports-color@7.2.0) + remark-math: 6.0.0(supports-color@7.2.0) shadcn: 4.16.2(supports-color@7.2.0)(typescript@6.0.3) + shiki: 4.4.2 sonner: 2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8) tailwind-merge: 3.6.0 tw-animate-css: 1.4.0 + unist-util-visit: 5.1.0 vaul: 1.1.2(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) transitivePeerDependencies: - '@cfworker/json-schema' @@ -5576,38 +5972,7 @@ snapshots: - '@types/react-dom' - babel-plugin-macros - date-fns - - react-is - - redux - - supports-color - - typescript - - '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@7.0.2)': - dependencies: - '@base-ui/react': 1.7.0(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@tauri-apps/api': 2.11.1 - class-variance-authority: 0.7.1 - clsx: 2.1.1 - cmdk: 1.1.1(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - embla-carousel-react: 8.6.0(react@19.2.8) - input-otp: 1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - lucide-react: 1.30.0(react@19.2.8) - next-themes: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - react: 19.2.8 - react-dom: 19.2.8(react@19.2.8) - react-resizable-panels: 4.12.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - recharts: 3.10.1(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1) - shadcn: 4.16.2(supports-color@7.2.0)(typescript@7.0.2) - sonner: 2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - tailwind-merge: 3.6.0 - tw-animate-css: 1.4.0 - vaul: 1.1.2(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - transitivePeerDependencies: - - '@cfworker/json-schema' - - '@date-fns/tz' - - '@types/react' - - '@types/react-dom' - - babel-plugin-macros - - date-fns + - emojibase - react-is - redux - supports-color @@ -5870,6 +6235,46 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} + '@shikijs/core@4.4.2': + dependencies: + '@shikijs/primitive': 4.4.2 + '@shikijs/types': 4.4.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@4.4.2': + dependencies: + '@shikijs/types': 4.4.2 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.6 + + '@shikijs/engine-oniguruma@4.4.2': + dependencies: + '@shikijs/types': 4.4.2 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@4.4.2': + dependencies: + '@shikijs/types': 4.4.2 + + '@shikijs/primitive@4.4.2': + dependencies: + '@shikijs/types': 4.4.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/themes@4.4.2': + dependencies: + '@shikijs/types': 4.4.2 + + '@shikijs/types@4.4.2': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/vscode-textmate@10.0.2': {} + '@sindresorhus/is@4.6.0': {} '@sindresorhus/merge-streams@4.0.0': {} @@ -6086,15 +6491,6 @@ snapshots: minimatch: 10.2.6 path-browserify: 1.0.1 - '@twemoji/api@17.0.3': - dependencies: - '@twemoji/parser': 17.0.2 - fs-extra: 8.1.0 - jsonfile: 5.0.0 - universalify: 0.1.2 - - '@twemoji/parser@17.0.2': {} - '@types/cacheable-request@6.0.3': dependencies: '@types/http-cache-semantics': 4.2.0 @@ -6141,20 +6537,34 @@ snapshots: '@types/esrecurse@4.3.1': {} + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.9 + '@types/estree@1.0.9': {} '@types/fs-extra@9.0.13': dependencies: '@types/node': 26.2.0 + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + '@types/http-cache-semantics@4.2.0': {} '@types/json-schema@7.0.15': {} + '@types/katex@0.16.8': {} + '@types/keyv@3.1.4': dependencies: '@types/node': 26.2.0 + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/ms@2.1.0': {} '@types/node@24.13.3': @@ -6181,6 +6591,10 @@ snapshots: dependencies: '@types/node': 26.2.0 + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + '@types/use-sync-external-store@0.0.6': {} '@types/validate-npm-package-name@4.0.2': {} @@ -6336,6 +6750,8 @@ snapshots: '@typescript/typescript-win32-x64@7.0.2': optional: true + '@ungap/structured-clone@1.3.3': {} + '@vitejs/plugin-react@6.0.5(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 @@ -6509,6 +6925,8 @@ snapshots: aws4@1.13.2: {} + bail@2.0.2: {} + balanced-match@1.0.2: {} balanced-match@4.0.4: {} @@ -6623,6 +7041,8 @@ snapshots: caniuse-lite@1.0.30001809: {} + ccount@2.0.1: {} + chai@6.2.2: {} chalk@4.1.2: @@ -6632,6 +7052,14 @@ snapshots: chalk@5.6.2: {} + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + chownr@3.0.0: {} chromium-pickle-js@0.2.0: {} @@ -6686,12 +7114,16 @@ snapshots: dependencies: delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} + commander@11.1.0: {} commander@14.0.3: {} commander@5.1.0: {} + commander@8.3.0: {} + commander@9.5.0: optional: true @@ -6742,15 +7174,6 @@ snapshots: optionalDependencies: typescript: 6.0.3 - cosmiconfig@9.0.2(typescript@7.0.2): - dependencies: - env-paths: 2.2.1 - import-fresh: 3.3.1 - js-yaml: 4.3.1 - parse-json: 5.2.0 - optionalDependencies: - typescript: 7.0.2 - crelt@1.0.7: {} cross-dirname@0.1.0: @@ -6816,6 +7239,10 @@ snapshots: decimal.js-light@2.5.1: {} + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 @@ -6861,6 +7288,8 @@ snapshots: depd@2.0.0: {} + dequal@2.0.3: {} + detect-libc@2.1.2: {} detect-node-es@1.1.0: {} @@ -6868,6 +7297,10 @@ snapshots: detect-node@2.1.0: optional: true + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + diff@8.0.4: {} dir-compare@4.2.0: @@ -7012,6 +7445,8 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + entities@6.0.1: {} + env-paths@2.2.1: {} env-paths@3.0.0: {} @@ -7079,6 +7514,8 @@ snapshots: escape-string-regexp@4.0.0: {} + escape-string-regexp@5.0.0: {} + eslint-plugin-react-hooks@7.1.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: '@babel/core': 7.29.7(supports-color@7.2.0) @@ -7156,6 +7593,8 @@ snapshots: estraverse@5.3.0: {} + estree-util-is-identifier-name@3.0.0: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.9 @@ -7246,6 +7685,8 @@ snapshots: transitivePeerDependencies: - supports-color + extend@3.0.2: {} + fallow-type-aware@3.14.0: dependencies: typescript: 7.0.2 @@ -7438,6 +7879,8 @@ snapshots: '@sec-ant/readable-stream': 0.4.1 is-stream: 4.0.1 + github-slugger@2.0.0: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -7508,6 +7951,108 @@ snapshots: dependencies: function-bind: 1.1.2 + hast-util-from-dom@5.0.1: + dependencies: + '@types/hast': 3.0.5 + hastscript: 9.0.1 + web-namespaces: 2.0.1 + + hast-util-from-html-isomorphic@2.0.0: + dependencies: + '@types/hast': 3.0.5 + hast-util-from-dom: 5.0.1 + hast-util-from-html: 2.0.3 + unist-util-remove-position: 5.0.0 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.5 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.2.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-heading-rank@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.5 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6(supports-color@7.2.0): + dependencies: + '@types/estree': 1.0.9 + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1(supports-color@7.2.0) + mdast-util-mdx-jsx: 3.2.0(supports-color@7.2.0) + mdast-util-mdxjs-esm: 2.0.1(supports-color@7.2.0) + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-string@3.0.1: + dependencies: + '@types/hast': 3.0.5 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.5 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + hermes-estree@0.25.1: {} hermes-parser@0.25.1: @@ -7520,6 +8065,10 @@ snapshots: dependencies: lru-cache: 6.0.0 + html-url-attributes@3.0.1: {} + + html-void-elements@3.0.0: {} + http-cache-semantics@4.2.0: {} http-errors@2.0.1: @@ -7577,6 +8126,8 @@ snapshots: inherits@2.0.4: {} + inline-style-parser@0.2.7: {} + input-otp@1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: react: 19.2.8 @@ -7588,8 +8139,17 @@ snapshots: ipaddr.js@1.9.1: {} + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + is-arrayish@0.2.1: {} + is-decimal@2.0.1: {} + is-docker@2.2.1: {} is-docker@3.0.0: {} @@ -7602,6 +8162,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-hexadecimal@2.0.1: {} + is-in-ssh@1.0.0: {} is-inside-container@1.0.0: @@ -7693,18 +8255,20 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - jsonfile@5.0.0: - dependencies: - universalify: 0.1.2 - optionalDependencies: - graceful-fs: 4.2.11 - jsonfile@6.2.1: dependencies: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 + katex@0.16.47: + dependencies: + commander: 8.3.0 + + katex@0.18.2: + dependencies: + commander: 8.3.0 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -7855,6 +8419,8 @@ snapshots: loglevel@1.9.2: {} + longest-streak@3.1.0: {} + lowercase-keys@2.0.0: {} lru-cache@5.1.1: @@ -7873,6 +8439,8 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + markdown-table@3.0.4: {} + matcher@3.0.0: dependencies: escape-string-regexp: 4.0.0 @@ -7880,6 +8448,176 @@ snapshots: math-intrinsics@1.1.0: {} + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2(supports-color@7.2.0) + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0(supports-color@7.2.0): + dependencies: + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0(supports-color@7.2.0) + mdast-util-gfm-strikethrough: 2.0.0(supports-color@7.2.0) + mdast-util-gfm-table: 2.0.0(supports-color@7.2.0) + mdast-util-gfm-task-list-item: 2.0.0(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-math@3.0.0(supports-color@7.2.0): + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + longest-streak: 3.1.0 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + unist-util-remove-position: 5.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1(supports-color@7.2.0): + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0(supports-color@7.2.0): + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1(supports-color@7.2.0): + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-newline-to-break@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-find-and-replace: 3.0.2 + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.3 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + media-typer@1.1.1: {} merge-descriptors@2.0.0: {} @@ -7888,6 +8626,207 @@ snapshots: merge2@1.4.1: {} + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-math@3.1.0: + dependencies: + '@types/katex': 0.16.8 + devlop: 1.1.0 + katex: 0.16.47 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2(supports-color@7.2.0): + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3(supports-color@7.2.0) + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -8043,6 +8982,14 @@ snapshots: dependencies: mimic-function: 5.0.1 + oniguruma-parser@0.12.2: {} + + oniguruma-to-es@4.3.6: + dependencies: + oniguruma-parser: 0.12.2 + regex: 6.1.0 + regex-recursion: 6.0.2 + open@11.0.0: dependencies: default-browser: 5.5.0 @@ -8103,6 +9050,16 @@ snapshots: dependencies: callsites: 3.1.0 + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.29.7 @@ -8112,6 +9069,10 @@ snapshots: parse-ms@4.0.0: {} + parse5@7.3.0: + dependencies: + entities: 6.0.1 + parseurl@1.3.3: {} path-browserify@1.0.1: {} @@ -8207,6 +9168,8 @@ snapshots: retry: 0.12.0 signal-exit: 3.0.7 + property-information@7.2.0: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -8250,6 +9213,24 @@ snapshots: react-is@19.2.8: {} + react-markdown@10.1.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0): + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/react': 19.2.18 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6(supports-color@7.2.0) + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.1 + react: 19.2.8 + remark-parse: 11.0.0(supports-color@7.2.0) + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + react-redux@9.3.0(@types/react@19.2.18)(react@19.2.8)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 @@ -8343,6 +9324,92 @@ snapshots: redux@5.0.1: {} + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + rehype-autolink-headings@7.1.0: + dependencies: + '@types/hast': 3.0.5 + '@ungap/structured-clone': 1.3.3 + hast-util-heading-rank: 3.0.0 + hast-util-is-element: 3.0.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + + rehype-katex@7.0.1: + dependencies: + '@types/hast': 3.0.5 + '@types/katex': 0.16.8 + hast-util-from-html-isomorphic: 2.0.0 + hast-util-to-text: 4.0.2 + katex: 0.16.47 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + + rehype-slug@6.0.0: + dependencies: + '@types/hast': 3.0.5 + github-slugger: 2.0.0 + hast-util-heading-rank: 3.0.0 + hast-util-to-string: 3.0.1 + unist-util-visit: 5.1.0 + + remark-breaks@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-newline-to-break: 2.0.0 + unified: 11.0.5 + + remark-gfm@4.0.1(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0(supports-color@7.2.0) + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0(supports-color@7.2.0) + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-math@6.0.0(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + mdast-util-math: 3.0.0(supports-color@7.2.0) + micromark-extension-math: 3.1.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -8529,52 +9596,23 @@ snapshots: - supports-color - typescript - shadcn@4.16.2(supports-color@7.2.0)(typescript@7.0.2): - dependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) - '@babel/parser': 7.29.8 - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) - '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) - '@dotenvx/dotenvx': 1.75.1 - '@modelcontextprotocol/sdk': 1.30.0(supports-color@7.2.0)(zod@3.25.76) - '@types/validate-npm-package-name': 4.0.2 - browserslist: 4.28.7 - commander: 14.0.3 - cosmiconfig: 9.0.2(typescript@7.0.2) - dedent: 1.7.2 - deepmerge: 4.3.1 - diff: 8.0.4 - execa: 9.6.1 - fast-glob: 3.3.3 - fs-extra: 11.4.0 - fuzzysort: 3.1.0 - kleur: 4.1.5 - open: 11.0.0 - ora: 8.2.0 - postcss: 8.5.26 - postcss-selector-parser: 7.1.5 - prompts: 2.4.2 - recast: 0.23.19 - stringify-object: 5.0.0 - tailwind-merge: 3.6.0 - ts-morph: 26.0.0 - tsconfig-paths: 4.2.0 - undici: 7.29.0 - validate-npm-package-name: 7.0.2 - zod: 3.25.76 - zod-to-json-schema: 3.25.2(zod@3.25.76) - transitivePeerDependencies: - - '@cfworker/json-schema' - - babel-plugin-macros - - supports-color - - typescript - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} + shiki@4.4.2: + dependencies: + '@shikijs/core': 4.4.2 + '@shikijs/engine-javascript': 4.4.2 + '@shikijs/engine-oniguruma': 4.4.2 + '@shikijs/langs': 4.4.2 + '@shikijs/themes': 4.4.2 + '@shikijs/types': 4.4.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + side-channel-list@1.0.1: dependencies: es-errors: 1.3.0 @@ -8629,6 +9667,8 @@ snapshots: source-map@0.6.1: {} + space-separated-tokens@2.0.2: {} + sprintf-js@1.1.3: optional: true @@ -8658,6 +9698,11 @@ snapshots: dependencies: safe-buffer: 5.1.2 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + stringify-object@5.0.0: dependencies: get-own-enumerable-keys: 1.0.0 @@ -8680,6 +9725,14 @@ snapshots: style-mod@4.1.3: {} + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + sumchecker@3.0.1(supports-color@7.2.0): dependencies: debug: 4.4.3(supports-color@7.2.0) @@ -8749,6 +9802,10 @@ snapshots: toidentifier@1.0.1: {} + trim-lines@3.0.1: {} + + trough@2.2.0: {} + truncate-utf8-bytes@1.0.2: dependencies: utf8-byte-length: 1.0.5 @@ -8836,6 +9893,49 @@ snapshots: unicorn-magic@0.3.0: {} + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + universalify@0.1.2: {} universalify@2.0.1: {} @@ -8901,6 +10001,21 @@ snapshots: - '@types/react' - '@types/react-dom' + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + victory-vendor@37.3.6: dependencies: '@types/d3-array': 3.2.2 @@ -8961,6 +10076,8 @@ snapshots: w3c-keyname@2.2.8: {} + web-namespaces@2.0.1: {} + webcrypto-core@1.9.2: dependencies: '@peculiar/asn1-schema': 2.8.0 @@ -9059,3 +10176,5 @@ snapshots: immer: 11.1.16 react: 19.2.8 use-sync-external-store: 1.6.0(react@19.2.8) + + zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 87d0c28..2bcade5 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,5 +6,5 @@ allowBuilds: electron-winstaller: true esbuild: true overrides: - "@methanium/ui": "https://git.methanium.net/methanium/ui/releases/download/0.0.22/methanium-ui.tgz" + "@methanium/ui": "https://git.methanium.net/methanium/ui/releases/download/0.0.28/methanium-ui.tgz" mtp: "https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz" From f1af0f210d114a975d406e51022eaa4e7fe39fe7 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Mon, 10 Aug 2026 11:00:32 +0200 Subject: [PATCH 69/97] chore(deps): update tauri-build digest to e2e585a --- apps/tauri/src-tauri/Cargo.lock | 8 ++++---- apps/tauri/src-tauri/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index 9171fc5..8e5d93d 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -5126,7 +5126,7 @@ dependencies = [ [[package]] name = "tauri-build" version = "2.6.3" -source = "git+https://github.com/tauri-apps/tauri?rev=c0bd0d5a61eedba5c4783add24455c5028c6f390#c0bd0d5a61eedba5c4783add24455c5028c6f390" +source = "git+https://github.com/tauri-apps/tauri?rev=e2e585ad1196c9572f86ef39aae01ef4c3b1a762#e2e585ad1196c9572f86ef39aae01ef4c3b1a762" dependencies = [ "anyhow", "cargo_toml", @@ -5138,7 +5138,7 @@ dependencies = [ "semver", "serde", "serde_json", - "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=c0bd0d5a61eedba5c4783add24455c5028c6f390)", + "tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=e2e585ad1196c9572f86ef39aae01ef4c3b1a762)", "tauri-winres", "walkdir", ] @@ -5418,7 +5418,7 @@ dependencies = [ [[package]] name = "tauri-utils" version = "2.9.3" -source = "git+https://github.com/tauri-apps/tauri?rev=c0bd0d5a61eedba5c4783add24455c5028c6f390#c0bd0d5a61eedba5c4783add24455c5028c6f390" +source = "git+https://github.com/tauri-apps/tauri?rev=e2e585ad1196c9572f86ef39aae01ef4c3b1a762#e2e585ad1196c9572f86ef39aae01ef4c3b1a762" dependencies = [ "anyhow", "cargo_metadata", @@ -5507,7 +5507,7 @@ dependencies = [ "serde", "serde_json", "tauri", - "tauri-build 2.6.3 (git+https://github.com/tauri-apps/tauri?rev=c0bd0d5a61eedba5c4783add24455c5028c6f390)", + "tauri-build 2.6.3 (git+https://github.com/tauri-apps/tauri?rev=e2e585ad1196c9572f86ef39aae01ef4c3b1a762)", "tauri-plugin-barcode-scanner", "tauri-plugin-deep-link", "tauri-plugin-log", diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index 19fe954..a13e4ab 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -15,7 +15,7 @@ name = "mobile_lib" crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] -tauri-build = { git = "https://github.com/tauri-apps/tauri", rev = "c0bd0d5a61eedba5c4783add24455c5028c6f390", features = [] } +tauri-build = { git = "https://github.com/tauri-apps/tauri", rev = "e2e585ad1196c9572f86ef39aae01ef4c3b1a762", features = [] } [dependencies] tauri-plugin-opener = "2" From c1baf3576ddb0f797c043e77ba4980ee521b3a3f Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Mon, 10 Aug 2026 12:00:36 +0200 Subject: [PATCH 70/97] chore(deps): update dependency org.jetbrains.kotlin:kotlin-gradle-plugin to v2.4.10 --- apps/tauri/src-tauri/gen/android/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tauri/src-tauri/gen/android/build.gradle.kts b/apps/tauri/src-tauri/gen/android/build.gradle.kts index 00024b5..6c0f95d 100644 --- a/apps/tauri/src-tauri/gen/android/build.gradle.kts +++ b/apps/tauri/src-tauri/gen/android/build.gradle.kts @@ -7,7 +7,7 @@ buildscript { } dependencies { classpath("com.android.tools.build:gradle:8.13.2") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.20") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.4.10") } } From 41258a848398a847518b1154c3ab3f4a273572aa Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Mon, 10 Aug 2026 13:00:39 +0200 Subject: [PATCH 71/97] chore(deps): update rust crate reqwest to 0.13 --- apps/tauri/src-tauri/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index a13e4ab..3c70f02 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -22,7 +22,7 @@ tauri-plugin-opener = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" base64 = "0.22" -reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } +reqwest = { version = "0.13", default-features = false, features = ["json", "rustls-tls"] } tokio = { version = "1", features = ["rt-multi-thread", "sync", "time"] } mtp = { git = "https://git.methanium.net/methanium/mtp.git", rev = "7182272e3edb0079d7b74b45b2f62a298d2fee22", features = ["client", "crypto"] } mtp-transport = { git = "https://git.methanium.net/methanium/mtp.git", rev = "b067614a684eb1856bc5db7b3fd82148c036ce6b" } From 1c90a0c85985f3e93959cbfa907d68cf2c03440b Mon Sep 17 00:00:00 2001 From: Alois Date: Mon, 10 Aug 2026 13:48:32 +0200 Subject: [PATCH 72/97] feat(status): make the set-status menu work feat(user): optimise get() function for react qol(todos): update todos --- apps/web/src/components/modals/basic.tsx | 8 +- apps/web/src/components/modals/profile.tsx | 15 +- apps/web/src/components/navbar.tsx | 9 + apps/web/src/components/sidebar.tsx | 35 +- apps/web/src/components/status-options.ts | 2 +- .../conversation/modal/conversation.tsx | 7 + .../call/src/components/buttons/invite.tsx | 1 + packages/call/src/components/invitePopup.tsx | 1 + packages/call/src/components/modals/base.tsx | 39 +- .../src/components/modals/contextMenu.tsx | 3 +- packages/call/src/components/popout.tsx | 29 +- packages/call/src/components/top.tsx | 101 +++-- packages/call/src/store.tsx | 10 +- packages/call/src/views/preview.tsx | 53 +-- packages/chat/src/components/media.tsx | 9 +- packages/chat/src/components/message.tsx | 21 +- packages/chat/src/components/replyBox.tsx | 9 +- packages/chat/src/context.tsx | 2 +- packages/chat/src/screen.tsx | 1 + packages/chat/todo.md | 1 + packages/notifications/src/context.tsx | 6 +- packages/notifications/todo.md | 2 - packages/settings/src/pages/profile.tsx | 51 ++- packages/shared/src/data.ts | 9 +- packages/storage/todo.md | 1 - packages/user/package.json | 1 + packages/user/src/context.tsx | 353 ++++++++++++++---- packages/user/src/selection.test.ts | 28 ++ packages/user/src/selection.ts | 40 ++ packages/user/src/wrapper.tsx | 51 ++- 30 files changed, 573 insertions(+), 325 deletions(-) create mode 100644 packages/user/src/selection.test.ts create mode 100644 packages/user/src/selection.ts diff --git a/apps/web/src/components/modals/basic.tsx b/apps/web/src/components/modals/basic.tsx index 46eaa45..dc4e48a 100644 --- a/apps/web/src/components/modals/basic.tsx +++ b/apps/web/src/components/modals/basic.tsx @@ -15,7 +15,10 @@ export function Basic({ user, extra, }: { - user: User; + user: Pick< + User, + "Display" | "Username" | "Avatar" | "OnlineStatus" | "Status" + >; extra?: React.ReactNode; }) { const display = user.Display || user.Username || "Unknown"; @@ -57,8 +60,9 @@ export function Basic({
    -
    +

    {display}

    +

    {user.Status}

    {extra}
    diff --git a/apps/web/src/components/modals/profile.tsx b/apps/web/src/components/modals/profile.tsx index 6324ab5..a4bddb2 100644 --- a/apps/web/src/components/modals/profile.tsx +++ b/apps/web/src/components/modals/profile.tsx @@ -4,7 +4,20 @@ import { Text } from "@methanium/ui/markdown"; import { ChevronDown, ChevronUp } from "lucide-react"; import { useState } from "react"; -export default function Profile({ user }: { user: User }) { +export default function Profile({ + user, +}: { + user: Pick< + User, + | "UserId" + | "Display" + | "Username" + | "Avatar" + | "About" + | "IotaId" + | "PublicKey" + >; +}) { const [showAdvancedInformation, setShowAdvancedInformation] = useState(false); return ( diff --git a/apps/web/src/components/navbar.tsx b/apps/web/src/components/navbar.tsx index 6c86f96..2f1c115 100644 --- a/apps/web/src/components/navbar.tsx +++ b/apps/web/src/components/navbar.tsx @@ -91,6 +91,15 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) { {pathname === "/chat" && id && ( isMobile ? (

    {user?.Display}

    diff --git a/apps/web/src/components/sidebar.tsx b/apps/web/src/components/sidebar.tsx index 7a7c58b..6c3de28 100644 --- a/apps/web/src/components/sidebar.tsx +++ b/apps/web/src/components/sidebar.tsx @@ -35,7 +35,7 @@ import SidebarBox from "@tensamin/call/sidebarBox"; import { useShowMobileNavbar } from "@/routes/app/useShowMobileNavbar"; import { Ellipsis, Check } from "lucide-react"; import { useState } from "react"; -import type { User } from "@tensamin/user/context"; +import { useUser, type User } from "@tensamin/user/context"; import { mtp, userPresencePreferenceSchema } from "@tensamin/shared/data"; import { useMTP } from "@tensamin/mtp"; import { @@ -64,7 +64,7 @@ function StatusDialog({ saveSucceeded, setSaveSucceeded, }: { - user: User; + user: Pick; open: boolean; onOpenChange: (open: boolean) => void; send: ReturnType["send"]; @@ -77,6 +77,8 @@ function StatusDialog({ saveSucceeded: boolean; setSaveSucceeded: (value: boolean) => void; }) { + const { updateProfile, updateState } = useUser(); + return ( Cancel} />
    diff --git a/packages/call/src/components/buttons/invite.tsx b/packages/call/src/components/buttons/invite.tsx index b478529..d49a643 100644 --- a/packages/call/src/components/buttons/invite.tsx +++ b/packages/call/src/components/buttons/invite.tsx @@ -63,6 +63,7 @@ export default function InviteButton({ Loading...
    } component={(user) => ( + {selectedGroup.name} +
    + ) : groups.length > 0 ? ( +
    + {sortedGroups.map((group) => ( + + ))} +
    + ) : null} + + {visibleUrls.length === 0 ? ( +
    + {selectedGroup ? "This group is empty." : "No ungrouped media."} +
    + ) : null} +
    {columns.map((column, columnIndex) => (
    @@ -504,6 +563,7 @@ function SavedPanel({ ariaLabel="Unsave media" defaultSaved onSavedMediaChange={onSavedMediaChange} + onSavedMediaGroupsChange={onSavedMediaGroupsChange} url={url} />
    @@ -530,6 +590,9 @@ export default function GifPicker({ const [searchString, setSearchString] = useState(""); const [debouncedSearchString, setDebouncedSearchString] = useState(""); const [savedMedia, setSavedMedia] = useState([]); + const [savedMediaGroups, setSavedMediaGroups] = useState< + ChatPickerMediaGroup[] + >([]); const didLoadLastTabRef = useRef(false); const searchDebouncerRef = useRef void> | null>( null, @@ -555,7 +618,13 @@ export default function GifPicker({ useEffect(() => { if (tab !== "saved") return; - void load("chat_picker_saved_media").then(setSavedMedia); + void Promise.all([ + load("chat_picker_saved_media"), + load("chat_picker_saved_media_groups"), + ]).then(([nextSavedMedia, nextGroups]) => { + setSavedMedia(nextSavedMedia); + setSavedMediaGroups(nextGroups); + }); }, [load, tab]); useEffect(() => { @@ -627,8 +696,10 @@ export default function GifPicker({ className="flex min-h-0 w-full flex-col overflow-hidden" > diff --git a/packages/chat/src/components/media.tsx b/packages/chat/src/components/media/media.tsx similarity index 100% rename from packages/chat/src/components/media.tsx rename to packages/chat/src/components/media/media.tsx diff --git a/packages/chat/src/components/media/mediaGroups.ts b/packages/chat/src/components/media/mediaGroups.ts new file mode 100644 index 0000000..1103781 --- /dev/null +++ b/packages/chat/src/components/media/mediaGroups.ts @@ -0,0 +1,65 @@ +import type { ChatPickerMediaGroup } from "@tensamin/shared/data"; + +function withoutMedia( + groups: ChatPickerMediaGroup[], + url: string, + keepGroupId?: string, +) { + return groups + .map((group) => ({ + ...group, + media: group.media.filter((item) => item !== url), + })) + .filter((group) => group.id === keepGroupId || group.media.length > 0); +} + +export function assignMediaToGroup( + groups: ChatPickerMediaGroup[], + groupId: string | null, + url: string, +) { + const nextGroups = withoutMedia(groups, url, groupId ?? undefined); + + if (groupId === null) return nextGroups; + + return nextGroups.map((group) => + group.id === groupId ? { ...group, media: [url, ...group.media] } : group, + ); +} + +export function createMediaGroup( + groups: ChatPickerMediaGroup[], + id: string, + name: string, + url: string, +) { + const trimmedName = name.trim(); + + if ( + !trimmedName || + groups.some( + (group) => + group.name.toLocaleLowerCase() === trimmedName.toLocaleLowerCase(), + ) + ) { + return groups; + } + + return [ + ...withoutMedia(groups, url), + { id, name: trimmedName, media: [url] }, + ]; +} + +export function getMediaGroupId(groups: ChatPickerMediaGroup[], url: string) { + return groups.find((group) => group.media.includes(url))?.id ?? null; +} + +export function getUngroupedMedia( + savedMedia: string[], + groups: ChatPickerMediaGroup[], +) { + const groupedMedia = new Set(groups.flatMap((group) => group.media)); + + return savedMedia.filter((url) => !groupedMedia.has(url)); +} diff --git a/packages/chat/src/components/media/mediaSaveButton.tsx b/packages/chat/src/components/media/mediaSaveButton.tsx new file mode 100644 index 0000000..e585eae --- /dev/null +++ b/packages/chat/src/components/media/mediaSaveButton.tsx @@ -0,0 +1,238 @@ +import { + Button, + cn, + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + Input, + Label, + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, + useIsMobile, +} from "@methanium/ui"; +import type { ChatPickerMediaGroup } from "@tensamin/shared/data"; +import { useStorage } from "@tensamin/storage/context"; +import { Ellipsis, Star } from "lucide-react"; +import { useEffect, useState } from "react"; +import { + assignMediaToGroup, + createMediaGroup, + getMediaGroupId, +} from "./mediaGroups"; + +export default function MediaSaveButton({ + ariaLabel, + className, + defaultSaved = false, + onSavedMediaChange, + onSavedMediaGroupsChange, + url, +}: { + ariaLabel?: string; + className?: string; + defaultSaved?: boolean; + onSavedMediaChange?: (savedMedia: string[]) => void; + onSavedMediaGroupsChange?: (groups: ChatPickerMediaGroup[]) => void; + url: string; +}) { + const { load, save } = useStorage(); + const isMobile = useIsMobile(); + const [savedMedia, setSavedMedia] = useState(null); + const [groups, setGroups] = useState(null); + const [dialogOpen, setDialogOpen] = useState(false); + const [selectedGroupId, setSelectedGroupId] = useState(null); + const [newGroupName, setNewGroupName] = useState(""); + const isSaved = savedMedia ? savedMedia.includes(url) : defaultSaved; + const sortedGroups = [...(groups ?? [])].sort((left, right) => + left.name.localeCompare(right.name), + ); + const normalizedNewGroupName = newGroupName.trim().toLocaleLowerCase(); + const canCreateGroup = + normalizedNewGroupName.length > 0 && + !(groups ?? []).some( + (group) => group.name.toLocaleLowerCase() === normalizedNewGroupName, + ); + + useEffect(() => { + void Promise.all([ + load("chat_picker_saved_media"), + load("chat_picker_saved_media_groups"), + ]).then(([nextSavedMedia, nextGroups]) => { + setSavedMedia(nextSavedMedia); + setGroups(nextGroups); + }); + }, [load]); + + async function handleSaveClick(event: React.MouseEvent) { + event.stopPropagation(); + + const [currentSavedMedia, currentGroups] = await Promise.all([ + load("chat_picker_saved_media"), + load("chat_picker_saved_media_groups"), + ]); + const willUnsave = currentSavedMedia.includes(url); + const nextSavedMedia = willUnsave + ? currentSavedMedia.filter((item) => item !== url) + : [url, ...currentSavedMedia]; + + setSavedMedia(nextSavedMedia); + onSavedMediaChange?.(nextSavedMedia); + if (willUnsave) { + const nextGroups = assignMediaToGroup(currentGroups, null, url); + setGroups(nextGroups); + onSavedMediaGroupsChange?.(nextGroups); + await Promise.all([ + save("chat_picker_saved_media", nextSavedMedia), + save("chat_picker_saved_media_groups", nextGroups), + ]); + return; + } + + await save("chat_picker_saved_media", nextSavedMedia); + } + + async function handleGroupClick(event: React.MouseEvent) { + event.stopPropagation(); + + const currentGroups = await load("chat_picker_saved_media_groups"); + setGroups(currentGroups); + setSelectedGroupId(getMediaGroupId(currentGroups, url)); + setNewGroupName(""); + setDialogOpen(true); + } + + async function handleGroupSave() { + const currentGroups = await load("chat_picker_saved_media_groups"); + const nextGroups = assignMediaToGroup(currentGroups, selectedGroupId, url); + + setGroups(nextGroups); + onSavedMediaGroupsChange?.(nextGroups); + await save("chat_picker_saved_media_groups", nextGroups); + setDialogOpen(false); + } + + async function handleCreateGroup() { + if (!canCreateGroup) return; + + const currentGroups = await load("chat_picker_saved_media_groups"); + const groupId = crypto.randomUUID(); + const nextGroups = createMediaGroup( + currentGroups, + groupId, + newGroupName, + url, + ); + + setGroups(nextGroups); + setSelectedGroupId(groupId); + setNewGroupName(""); + onSavedMediaGroupsChange?.(nextGroups); + await save("chat_picker_saved_media_groups", nextGroups); + setDialogOpen(false); + } + + return ( + <> +
    + + {isSaved ? ( + + ) : null} +
    + + + event.stopPropagation()}> + + Organize saved media + + +
    +
    + + +
    + +
    + +
    + setNewGroupName(event.target.value)} + onKeyDown={(event) => { + if (event.key === "Enter") void handleCreateGroup(); + }} + /> + +
    +
    +
    + + + + + +
    +
    + + ); +} diff --git a/packages/chat/src/components/mediaSaveButton.tsx b/packages/chat/src/components/mediaSaveButton.tsx deleted file mode 100644 index 99fbcec..0000000 --- a/packages/chat/src/components/mediaSaveButton.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { Button, cn, useIsMobile } from "@methanium/ui"; -import { useStorage } from "@tensamin/storage/context"; -import { Star } from "lucide-react"; -import { useEffect, useState } from "react"; - -export default function MediaSaveButton({ - ariaLabel, - className, - defaultSaved = false, - onSavedMediaChange, - url, -}: { - ariaLabel?: string; - className?: string; - defaultSaved?: boolean; - onSavedMediaChange?: (savedMedia: string[]) => void; - url: string; -}) { - const { load, save } = useStorage(); - const isMobile = useIsMobile(); - const [savedMedia, setSavedMedia] = useState(null); - const isSaved = savedMedia ? savedMedia.includes(url) : defaultSaved; - - useEffect(() => { - void load("chat_picker_saved_media").then(setSavedMedia); - }, [load]); - - async function handleClick(event: React.MouseEvent) { - event.stopPropagation(); - - const currentSavedMedia = - savedMedia ?? (await load("chat_picker_saved_media")); - const nextSavedMedia = currentSavedMedia.includes(url) - ? currentSavedMedia.filter((item) => item !== url) - : [url, ...currentSavedMedia]; - - setSavedMedia(nextSavedMedia); - onSavedMediaChange?.(nextSavedMedia); - void save("chat_picker_saved_media", nextSavedMedia); - } - - return ( - - ); -} diff --git a/packages/chat/src/components/message.tsx b/packages/chat/src/components/message.tsx index 4dd6624..cbcd37e 100644 --- a/packages/chat/src/components/message.tsx +++ b/packages/chat/src/components/message.tsx @@ -13,14 +13,14 @@ import { Skeleton, } from "@methanium/ui"; import MessageContextMenu from "./messageContextMenu"; -import Media from "./media"; +import Media from "./media/media"; import { useStorage } from "@tensamin/storage/context"; import { useMTP } from "@tensamin/mtp"; import { getMessage, useChat } from "../context"; import { decryptChatText, encryptChatText } from "@tensamin/crypto/chatSecret"; import { log, toast } from "@tensamin/shared/log"; import { Emoji, Input, normalizeShortcode, Text } from "@methanium/ui/markdown"; -import { useRecordEmojiUse } from "./emojiRanks"; +import { useRecordEmojiUse } from "./emoji/emojiRanks"; import ReplyBox from "./replyBox"; import { useHotkey } from "@tensamin/hotkeys"; import { cancelMessageEditHotkey } from "../hotkeys"; @@ -381,8 +381,8 @@ function MessageComponent({
    )} {editing ? ( -
    - +
    + +
    +
    + ); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bbfb6de..38033b2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -509,6 +509,9 @@ importers: '@tanstack/react-router': specifier: ^1.170.21 version: 1.170.23(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@tauri-apps/api': + specifier: ^2.11.1 + version: 2.11.1 '@tensamin/cache': specifier: workspace:* version: link:../cache From 6e977bca7e6c127591cadfa85f1b830ae79d659b Mon Sep 17 00:00:00 2001 From: Alois Date: Wed, 12 Aug 2026 02:16:56 +0200 Subject: [PATCH 77/97] feat(mobile): use drawer for gif picker fix(mobile): some ui bugs fix(mobile): disable pinch zooming --- apps/tauri/src-tauri/Cargo.lock | 2 +- .../java/net/tensamin/client/MainActivity.kt | 27 + apps/web/index.html | 5 +- apps/web/src/components/sidebar.tsx | 9 +- apps/web/src/index.tsx | 12 +- packages/chat/src/components/input.tsx | 96 ++-- packages/chat/src/components/media/media.tsx | 4 +- pnpm-lock.yaml | 538 +++++++++++------- pnpm-workspace.yaml | 2 +- 9 files changed, 436 insertions(+), 259 deletions(-) diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index 744d5a2..7a30247 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -5298,7 +5298,7 @@ dependencies = [ [[package]] name = "tensamin" -version = "0.0.11" +version = "0.0.0" dependencies = [ "base64 0.22.1", "jni 0.22.4", diff --git a/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/MainActivity.kt b/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/MainActivity.kt index fc3be18..66df13a 100644 --- a/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/MainActivity.kt +++ b/apps/tauri/src-tauri/gen/android/app/src/main/java/net/tensamin/client/MainActivity.kt @@ -5,6 +5,7 @@ import android.app.Activity import android.content.pm.PackageManager import android.media.projection.MediaProjectionManager import android.os.Bundle +import android.view.MotionEvent import android.view.ViewTreeObserver import android.view.WindowManager import android.webkit.JavascriptInterface @@ -54,6 +55,32 @@ class MainActivity : TauriActivity() { } override fun onWebViewCreate(webView: WebView) { + webView.settings.apply { + setSupportZoom(false) + builtInZoomControls = false + displayZoomControls = false + } + + var blockingMultiTouch = false + webView.setOnTouchListener { _, event -> + val shouldBlock = blockingMultiTouch || event.pointerCount > 1 + + when (event.actionMasked) { + MotionEvent.ACTION_POINTER_DOWN -> { + // Cancel the one-finger gesture before consuming the rest of the pinch. + MotionEvent.obtain(event).let { cancelEvent -> + cancelEvent.action = MotionEvent.ACTION_CANCEL + webView.onTouchEvent(cancelEvent) + cancelEvent.recycle() + } + blockingMultiTouch = true + } + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> blockingMultiTouch = false + } + + shouldBlock + } + NativeAccessibilityBridge.attach(webView) mediaWebView = webView MobileMediaEvents.attach(webView) diff --git a/apps/web/index.html b/apps/web/index.html index 01335eb..0c0644f 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -3,7 +3,10 @@ - + Tensamin diff --git a/apps/web/src/components/sidebar.tsx b/apps/web/src/components/sidebar.tsx index 6c3de28..d56a4f1 100644 --- a/apps/web/src/components/sidebar.tsx +++ b/apps/web/src/components/sidebar.tsx @@ -27,7 +27,6 @@ import { SelectContent, SelectItem, } from "@methanium/ui"; -import { isTauri } from "@tauri-apps/api/core"; import { useIsMobile } from "@methanium/ui"; import { MobileNavbar } from "./navbar"; @@ -194,11 +193,7 @@ export default function Sidebar() { const content = ( <> - +
    - + diff --git a/packages/chat/src/components/input.tsx b/packages/chat/src/components/input.tsx index 15c5c55..e7a8d6e 100644 --- a/packages/chat/src/components/input.tsx +++ b/packages/chat/src/components/input.tsx @@ -2,6 +2,11 @@ import { Input, type InputController } from "@methanium/ui/markdown"; import { Card, CardHeader, + Drawer, + DrawerContent, + DrawerDescription, + DrawerTitle, + DrawerTrigger, Popover, PopoverContent, PopoverTrigger, @@ -331,42 +336,65 @@ export default function InputComponent({ /> - - ( - - )} - /> - event.stopPropagation()} - onWheelCapture={(event) => event.stopPropagation()} - style={{ - ...gifPopoverSize, - maxHeight: gifPopoverSize?.height, - }} - > -
    + +
    + +
    +
    + +
    + { + void handleSubmit(url, true); + setGifPopoverOpen(false); + }} + /> +
    +
    + + ) : ( + + ( + + )} /> - { - void handleSubmit(url, true); - setGifPopoverOpen(false); + event.stopPropagation()} + onWheelCapture={(event) => event.stopPropagation()} + style={{ + ...gifPopoverSize, + maxHeight: gifPopoverSize?.height, }} - /> - - + > +
    + { + void handleSubmit(url, true); + setGifPopoverOpen(false); + }} + /> + + + )}
    diff --git a/packages/chat/src/components/media/media.tsx b/packages/chat/src/components/media/media.tsx index 02ee6ef..1072308 100644 --- a/packages/chat/src/components/media/media.tsx +++ b/packages/chat/src/components/media/media.tsx @@ -166,9 +166,9 @@ export default function Media({ -
    +
    =0.10.0'} @@ -5252,16 +5267,16 @@ snapshots: '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.7(supports-color@7.2.0)': + '@babel/core@7.29.7': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.8 '@babel/helper-compilation-targets': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) '@babel/helpers': 7.29.7 '@babel/parser': 7.29.8 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.8(supports-color@7.2.0) + '@babel/traverse': 7.29.8 '@babel/types': 7.29.8 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 @@ -5292,41 +5307,41 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/core': 7.29.7 '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@7.2.0) + '@babel/helper-member-expression-to-functions': 7.29.7 '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) - '@babel/traverse': 7.29.8(supports-color@7.2.0) + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/traverse': 7.29.8 semver: 6.3.1 transitivePeerDependencies: - supports-color '@babel/helper-globals@7.29.7': {} - '@babel/helper-member-expression-to-functions@7.29.7(supports-color@7.2.0)': + '@babel/helper-member-expression-to-functions@7.29.7': dependencies: - '@babel/traverse': 7.29.8(supports-color@7.2.0) + '@babel/traverse': 7.29.8 '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.29.7(supports-color@7.2.0)': + '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/traverse': 7.29.8(supports-color@7.2.0) + '@babel/traverse': 7.29.8 '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) - '@babel/helper-module-imports': 7.29.7(supports-color@7.2.0) + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.8(supports-color@7.2.0) + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -5336,18 +5351,18 @@ snapshots: '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) - '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@7.2.0) + '@babel/core': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/traverse': 7.29.8(supports-color@7.2.0) + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.29.7(supports-color@7.2.0)': + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': dependencies: - '@babel/traverse': 7.29.8(supports-color@7.2.0) + '@babel/traverse': 7.29.8 '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -5367,43 +5382,43 @@ snapshots: dependencies: '@babel/types': 7.29.8 - '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/core': 7.29.7 '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) - '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + '@babel/preset-typescript@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-option': 7.29.7 - '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) - '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) transitivePeerDependencies: - supports-color @@ -5415,7 +5430,7 @@ snapshots: '@babel/parser': 7.29.8 '@babel/types': 7.29.8 - '@babel/traverse@7.29.8(supports-color@7.2.0)': + '@babel/traverse@7.29.8': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.8 @@ -5572,7 +5587,7 @@ snapshots: fs-extra: 9.1.0 minimist: 1.2.8 - '@electron/get@3.1.0(supports-color@7.2.0)': + '@electron/get@3.1.0': dependencies: debug: 4.4.3(supports-color@7.2.0) env-paths: 2.2.1 @@ -5580,7 +5595,7 @@ snapshots: got: 11.8.6 progress: 2.0.3 semver: 6.3.1 - sumchecker: 3.0.1(supports-color@7.2.0) + sumchecker: 3.0.1 optionalDependencies: global-agent: 3.0.0 transitivePeerDependencies: @@ -5593,13 +5608,13 @@ snapshots: graceful-fs: 4.2.11 progress: 2.0.3 semver: 7.8.5 - sumchecker: 3.0.1(supports-color@7.2.0) + sumchecker: 3.0.1 optionalDependencies: undici: 7.29.0 transitivePeerDependencies: - supports-color - '@electron/notarize@2.5.0(supports-color@7.2.0)': + '@electron/notarize@2.5.0': dependencies: debug: 4.4.3(supports-color@7.2.0) fs-extra: 9.1.0 @@ -5607,7 +5622,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/osx-sign@1.3.3(supports-color@7.2.0)': + '@electron/osx-sign@1.3.3': dependencies: compare-version: 0.1.2 debug: 4.4.3(supports-color@7.2.0) @@ -5618,18 +5633,18 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/rebuild@4.2.0(supports-color@7.2.0)': + '@electron/rebuild@4.2.0': dependencies: '@malept/cross-spawn-promise': 2.0.0 debug: 4.4.3(supports-color@7.2.0) node-abi: 4.33.0 node-api-version: 0.2.1 node-gyp: 12.4.0 - read-binary-file-arch: 1.0.6(supports-color@7.2.0) + read-binary-file-arch: 1.0.6 transitivePeerDependencies: - supports-color - '@electron/universal@2.0.3(supports-color@7.2.0)': + '@electron/universal@2.0.3': dependencies: '@electron/asar': 3.4.1 '@malept/cross-spawn-promise': 2.0.0 @@ -5641,7 +5656,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/windows-sign@1.2.2(supports-color@7.2.0)': + '@electron/windows-sign@1.2.2': dependencies: cross-dirname: 0.1.0 debug: 4.4.3(supports-color@7.2.0) @@ -5735,6 +5750,11 @@ snapshots: eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.10.1(eslint@10.8.1(jiti@2.7.0))': + dependencies: + eslint: 10.8.1(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.12.2': {} '@eslint/config-array@0.23.5(supports-color@7.2.0)': @@ -5757,6 +5777,10 @@ snapshots: optionalDependencies: eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + '@eslint/js@10.0.1(eslint@10.8.1(jiti@2.7.0))': + optionalDependencies: + eslint: 10.8.1(jiti@2.7.0) + '@eslint/object-schema@3.0.5': {} '@eslint/plugin-kit@0.7.2': @@ -5918,7 +5942,7 @@ snapshots: dependencies: cross-spawn: 7.0.6 - '@malept/flatpak-bundler@0.4.0(supports-color@7.2.0)': + '@malept/flatpak-bundler@0.4.0': dependencies: debug: 4.4.3(supports-color@7.2.0) fs-extra: 9.1.0 @@ -5929,7 +5953,7 @@ snapshots: '@marijn/find-cluster-break@1.0.3': {} - '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.28/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3)': + '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3)': dependencies: '@base-ui/react': 1.7.0(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@codemirror/autocomplete': 6.20.3 @@ -5945,25 +5969,25 @@ snapshots: cmdk: 1.1.1(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) embla-carousel-react: 8.6.0(react@19.2.8) emojibase-data: 17.0.0(emojibase@17.0.0) - hast-util-to-jsx-runtime: 2.3.6(supports-color@7.2.0) + hast-util-to-jsx-runtime: 2.3.6 input-otp: 1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - katex: 0.18.2 - lucide-react: 1.30.0(react@19.2.8) + katex: 0.18.4 + lucide-react: 1.31.0(react@19.2.8) next-themes: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - react-markdown: 10.1.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) + react-markdown: 10.1.0(@types/react@19.2.18)(react@19.2.8) react-resizable-panels: 4.12.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) recharts: 3.10.1(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1) rehype-autolink-headings: 7.1.0 rehype-katex: 7.0.1 rehype-slug: 6.0.0 remark-breaks: 4.0.0 - remark-gfm: 4.0.1(supports-color@7.2.0) - remark-math: 6.0.0(supports-color@7.2.0) - shadcn: 4.16.2(supports-color@7.2.0)(typescript@6.0.3) + remark-gfm: 4.0.1 + remark-math: 6.0.0 + shadcn: 4.16.2(typescript@6.0.3) shiki: 4.4.2 - sonner: 2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + sonner: 2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) tailwind-merge: 3.6.0 tw-animate-css: 1.4.0 unist-util-visit: 5.1.0 @@ -5981,7 +6005,7 @@ snapshots: - supports-color - typescript - '@modelcontextprotocol/sdk@1.30.0(supports-color@7.2.0)(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.30.0(zod@3.25.76)': dependencies: '@hono/node-server': 2.1.0(hono@4.13.1) ajv: 8.20.0 @@ -5991,8 +6015,8 @@ snapshots: cross-spawn: 7.0.6 eventsource: 3.0.7 eventsource-parser: 3.1.0 - express: 5.2.1(supports-color@7.2.0) - express-rate-limit: 8.6.2(express@5.2.1(supports-color@7.2.0))(supports-color@7.2.0) + express: 5.2.1 + express-rate-limit: 8.6.2(express@5.2.1) hono: 4.13.1 jose: 6.2.8 json-schema-typed: 8.0.2 @@ -6608,7 +6632,7 @@ snapshots: '@typescript-eslint/parser': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.66.0 '@typescript-eslint/type-utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.66.0 eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) ignore: 7.0.6 @@ -6618,6 +6642,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.66.0 + '@typescript-eslint/type-utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.66.0 + eslint: 10.8.1(jiti@2.7.0) + ignore: 7.0.6 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.66.0 @@ -6630,6 +6670,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.66.0 + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.66.0 + debug: 4.4.3(supports-color@7.2.0) + eslint: 10.8.1(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/project-service@8.66.0(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.66.0(typescript@6.0.3) @@ -6652,7 +6704,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.66.0 '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3) debug: 4.4.3(supports-color@7.2.0) eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) ts-api-utils: 2.5.0(typescript@6.0.3) @@ -6660,6 +6712,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/type-utils@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + debug: 4.4.3(supports-color@7.2.0) + eslint: 10.8.1(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/types@8.66.0': {} '@typescript-eslint/typescript-estree@8.66.0(supports-color@7.2.0)(typescript@6.0.3)': @@ -6677,7 +6741,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + '@typescript-eslint/utils@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) '@typescript-eslint/scope-manager': 8.66.0 @@ -6688,6 +6752,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.66.0 + '@typescript-eslint/types': 8.66.0 + '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) + eslint: 10.8.1(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/visitor-keys@8.66.0': dependencies: '@typescript-eslint/types': 8.66.0 @@ -6850,33 +6925,33 @@ snapshots: dependencies: color-convert: 2.0.1 - app-builder-lib@26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): + app-builder-lib@26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3): dependencies: '@electron/asar': 3.4.1 '@electron/fuses': 1.8.0 - '@electron/get': 3.1.0(supports-color@7.2.0) - '@electron/notarize': 2.5.0(supports-color@7.2.0) - '@electron/osx-sign': 1.3.3(supports-color@7.2.0) - '@electron/rebuild': 4.2.0(supports-color@7.2.0) - '@electron/universal': 2.0.3(supports-color@7.2.0) - '@malept/flatpak-bundler': 0.4.0(supports-color@7.2.0) + '@electron/get': 3.1.0 + '@electron/notarize': 2.5.0 + '@electron/osx-sign': 1.3.3 + '@electron/rebuild': 4.2.0 + '@electron/universal': 2.0.3 + '@malept/flatpak-bundler': 0.4.0 '@noble/hashes': 2.3.0 '@peculiar/webcrypto': 1.7.1 '@types/fs-extra': 9.0.13 ajv: 8.20.0 asn1js: 3.0.10 async-exit-hook: 2.0.1 - builder-util: 26.15.3(supports-color@7.2.0) - builder-util-runtime: 9.7.0(supports-color@7.2.0) + builder-util: 26.15.3 + builder-util-runtime: 9.7.0 chromium-pickle-js: 0.2.0 ci-info: 4.3.1 debug: 4.4.3(supports-color@7.2.0) - dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) dotenv: 16.6.1 dotenv-expand: 11.0.7 ejs: 3.1.10 - electron-builder-squirrel-windows: 26.15.3(dmg-builder@26.15.3)(supports-color@7.2.0) - electron-publish: 26.15.3(supports-color@7.2.0) + electron-builder-squirrel-windows: 26.15.3(dmg-builder@26.15.3) + electron-publish: 26.15.3 fs-extra: 10.1.0 hosted-git-info: 4.1.0 isbinaryfile: 5.0.7 @@ -6940,7 +7015,7 @@ snapshots: bluebird@3.7.2: {} - body-parser@2.3.0(supports-color@7.2.0): + body-parser@2.3.0: dependencies: bytes: 3.1.2 content-type: 2.0.0 @@ -6984,23 +7059,23 @@ snapshots: buffer-from@1.1.2: {} - builder-util-runtime@9.7.0(supports-color@7.2.0): + builder-util-runtime@9.7.0: dependencies: debug: 4.4.3(supports-color@7.2.0) sax: 1.6.1 transitivePeerDependencies: - supports-color - builder-util@26.15.3(supports-color@7.2.0): + builder-util@26.15.3: dependencies: '@types/debug': 4.1.13 - builder-util-runtime: 9.7.0(supports-color@7.2.0) + builder-util-runtime: 9.7.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3(supports-color@7.2.0) fs-extra: 10.1.0 - http-proxy-agent: 7.0.2(supports-color@7.2.0) - https-proxy-agent: 7.0.6(supports-color@7.2.0) + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 js-yaml: 4.3.1 sanitize-filename: 1.6.4 source-map-support: 0.5.21 @@ -7311,10 +7386,10 @@ snapshots: minimatch: 3.1.5 p-limit: 3.1.0 - dmg-builder@26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): + dmg-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) - builder-util: 26.15.3(supports-color@7.2.0) + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) + builder-util: 26.15.3 fs-extra: 10.1.0 js-yaml: 4.3.1 transitivePeerDependencies: @@ -7349,23 +7424,23 @@ snapshots: dependencies: jake: 10.9.4 - electron-builder-squirrel-windows@26.15.3(dmg-builder@26.15.3)(supports-color@7.2.0): + electron-builder-squirrel-windows@26.15.3(dmg-builder@26.15.3): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) - builder-util: 26.15.3(supports-color@7.2.0) - electron-winstaller: 5.4.0(supports-color@7.2.0) + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) + builder-util: 26.15.3 + electron-winstaller: 5.4.0 transitivePeerDependencies: - dmg-builder - supports-color - electron-builder@26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): + electron-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) - builder-util: 26.15.3(supports-color@7.2.0) - builder-util-runtime: 9.7.0(supports-color@7.2.0) + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) + builder-util: 26.15.3 + builder-util-runtime: 9.7.0 chalk: 4.1.2 ci-info: 4.4.0 - dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) fs-extra: 10.1.0 lazy-val: 1.0.5 simple-update-notifier: 2.0.0 @@ -7374,12 +7449,12 @@ snapshots: - electron-builder-squirrel-windows - supports-color - electron-publish@26.15.3(supports-color@7.2.0): + electron-publish@26.15.3: dependencies: '@types/fs-extra': 9.0.13 aws4: 1.13.2 - builder-util: 26.15.3(supports-color@7.2.0) - builder-util-runtime: 9.7.0(supports-color@7.2.0) + builder-util: 26.15.3 + builder-util-runtime: 9.7.0 chalk: 4.1.2 form-data: 4.0.6 fs-extra: 10.1.0 @@ -7390,7 +7465,7 @@ snapshots: electron-to-chromium@1.5.402: {} - electron-winstaller@5.4.0(supports-color@7.2.0): + electron-winstaller@5.4.0: dependencies: '@electron/asar': 3.4.1 debug: 4.4.3(supports-color@7.2.0) @@ -7398,7 +7473,7 @@ snapshots: lodash: 4.18.1 temp: 0.9.4 optionalDependencies: - '@electron/windows-sign': 1.2.2(supports-color@7.2.0) + '@electron/windows-sign': 1.2.2 transitivePeerDependencies: - supports-color @@ -7519,9 +7594,9 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-plugin-react-hooks@7.1.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): + eslint-plugin-react-hooks@7.1.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)): dependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/core': 7.29.7 '@babel/parser': 7.29.8 eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) hermes-parser: 0.25.1 @@ -7541,6 +7616,43 @@ snapshots: eslint-visitor-keys@5.0.1: {} + eslint@10.8.1(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.23.5(supports-color@7.2.0) + '@eslint/config-helpers': 0.7.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.2 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@7.2.0) + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.6 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0): dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) @@ -7647,18 +7759,18 @@ snapshots: exponential-backoff@3.1.3: {} - express-rate-limit@8.6.2(express@5.2.1(supports-color@7.2.0))(supports-color@7.2.0): + express-rate-limit@8.6.2(express@5.2.1): dependencies: debug: 4.4.3(supports-color@7.2.0) - express: 5.2.1(supports-color@7.2.0) + express: 5.2.1 ip-address: 10.4.0 transitivePeerDependencies: - supports-color - express@5.2.1(supports-color@7.2.0): + express@5.2.1: dependencies: accepts: 2.0.0 - body-parser: 2.3.0(supports-color@7.2.0) + body-parser: 2.3.0 content-disposition: 1.1.0 content-type: 1.0.5 cookie: 0.7.2 @@ -7668,7 +7780,7 @@ snapshots: encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 2.1.1(supports-color@7.2.0) + finalhandler: 2.1.1 fresh: 2.0.0 http-errors: 2.0.1 merge-descriptors: 2.0.0 @@ -7679,9 +7791,9 @@ snapshots: proxy-addr: 2.0.7 qs: 6.15.3 range-parser: 1.3.0 - router: 2.2.0(supports-color@7.2.0) - send: 1.2.1(supports-color@7.2.0) - serve-static: 2.2.1(supports-color@7.2.0) + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 statuses: 2.0.2 type-is: 2.1.0 vary: 1.1.2 @@ -7749,7 +7861,7 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.1(supports-color@7.2.0): + finalhandler@2.1.1: dependencies: debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 @@ -8013,7 +8125,7 @@ snapshots: stringify-entities: 4.0.4 zwitch: 2.0.4 - hast-util-to-jsx-runtime@2.3.6(supports-color@7.2.0): + hast-util-to-jsx-runtime@2.3.6: dependencies: '@types/estree': 1.0.9 '@types/hast': 3.0.5 @@ -8022,9 +8134,9 @@ snapshots: devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 hast-util-whitespace: 3.0.0 - mdast-util-mdx-expression: 2.0.1(supports-color@7.2.0) - mdast-util-mdx-jsx: 3.2.0(supports-color@7.2.0) - mdast-util-mdxjs-esm: 2.0.1(supports-color@7.2.0) + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 property-information: 7.2.0 space-separated-tokens: 2.0.2 style-to-js: 1.1.21 @@ -8082,7 +8194,7 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 - http-proxy-agent@7.0.2(supports-color@7.2.0): + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 debug: 4.4.3(supports-color@7.2.0) @@ -8094,7 +8206,7 @@ snapshots: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - https-proxy-agent@7.0.6(supports-color@7.2.0): + https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 debug: 4.4.3(supports-color@7.2.0) @@ -8268,7 +8380,7 @@ snapshots: dependencies: commander: 8.3.0 - katex@0.18.2: + katex@0.18.4: dependencies: commander: 8.3.0 @@ -8438,6 +8550,10 @@ snapshots: dependencies: react: 19.2.8 + lucide-react@1.31.0(react@19.2.8): + dependencies: + react: 19.2.8 + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -8458,14 +8574,14 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - mdast-util-from-markdown@2.0.3(supports-color@7.2.0): + mdast-util-from-markdown@2.0.3: dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 decode-named-character-reference: 1.3.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 - micromark: 4.0.2(supports-color@7.2.0) + micromark: 4.0.2 micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-decode-string: 2.0.1 micromark-util-normalize-identifier: 2.0.1 @@ -8483,79 +8599,79 @@ snapshots: mdast-util-find-and-replace: 3.0.2 micromark-util-character: 2.1.1 - mdast-util-gfm-footnote@2.1.0(supports-color@7.2.0): + mdast-util-gfm-footnote@2.1.0: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: - supports-color - mdast-util-gfm-strikethrough@2.0.0(supports-color@7.2.0): + mdast-util-gfm-strikethrough@2.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm-table@2.0.0(supports-color@7.2.0): + mdast-util-gfm-table@2.0.0: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm-task-list-item@2.0.0(supports-color@7.2.0): + mdast-util-gfm-task-list-item@2.0.0: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm@3.1.0(supports-color@7.2.0): + mdast-util-gfm@3.1.0: dependencies: - mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-from-markdown: 2.0.3 mdast-util-gfm-autolink-literal: 2.0.1 - mdast-util-gfm-footnote: 2.1.0(supports-color@7.2.0) - mdast-util-gfm-strikethrough: 2.0.0(supports-color@7.2.0) - mdast-util-gfm-table: 2.0.0(supports-color@7.2.0) - mdast-util-gfm-task-list-item: 2.0.0(supports-color@7.2.0) + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-math@3.0.0(supports-color@7.2.0): + mdast-util-math@3.0.0: dependencies: '@types/hast': 3.0.5 '@types/mdast': 4.0.4 devlop: 1.1.0 longest-streak: 3.1.0 - mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 unist-util-remove-position: 5.0.0 transitivePeerDependencies: - supports-color - mdast-util-mdx-expression@2.0.1(supports-color@7.2.0): + mdast-util-mdx-expression@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.5 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-mdx-jsx@3.2.0(supports-color@7.2.0): + mdast-util-mdx-jsx@3.2.0: dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.5 @@ -8563,7 +8679,7 @@ snapshots: '@types/unist': 3.0.3 ccount: 2.0.1 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 parse-entities: 4.0.2 stringify-entities: 4.0.4 @@ -8572,13 +8688,13 @@ snapshots: transitivePeerDependencies: - supports-color - mdast-util-mdxjs-esm@2.0.1(supports-color@7.2.0): + mdast-util-mdxjs-esm@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.5 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -8808,7 +8924,7 @@ snapshots: micromark-util-types@2.0.2: {} - micromark@4.0.2(supports-color@7.2.0): + micromark@4.0.2: dependencies: '@types/debug': 4.1.13 debug: 4.4.3(supports-color@7.2.0) @@ -9216,17 +9332,17 @@ snapshots: react-is@19.2.8: {} - react-markdown@10.1.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0): + react-markdown@10.1.0(@types/react@19.2.18)(react@19.2.8): dependencies: '@types/hast': 3.0.5 '@types/mdast': 4.0.4 '@types/react': 19.2.18 devlop: 1.1.0 - hast-util-to-jsx-runtime: 2.3.6(supports-color@7.2.0) + hast-util-to-jsx-runtime: 2.3.6 html-url-attributes: 3.0.1 mdast-util-to-hast: 13.2.1 react: 19.2.8 - remark-parse: 11.0.0(supports-color@7.2.0) + remark-parse: 11.0.0 remark-rehype: 11.1.2 unified: 11.0.5 unist-util-visit: 5.1.0 @@ -9277,7 +9393,7 @@ snapshots: react@19.2.8: {} - read-binary-file-arch@1.0.6(supports-color@7.2.0): + read-binary-file-arch@1.0.6: dependencies: debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: @@ -9370,30 +9486,30 @@ snapshots: mdast-util-newline-to-break: 2.0.0 unified: 11.0.5 - remark-gfm@4.0.1(supports-color@7.2.0): + remark-gfm@4.0.1: dependencies: '@types/mdast': 4.0.4 - mdast-util-gfm: 3.1.0(supports-color@7.2.0) + mdast-util-gfm: 3.1.0 micromark-extension-gfm: 3.0.0 - remark-parse: 11.0.0(supports-color@7.2.0) + remark-parse: 11.0.0 remark-stringify: 11.0.0 unified: 11.0.5 transitivePeerDependencies: - supports-color - remark-math@6.0.0(supports-color@7.2.0): + remark-math@6.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-math: 3.0.0(supports-color@7.2.0) + mdast-util-math: 3.0.0 micromark-extension-math: 3.1.0 unified: 11.0.5 transitivePeerDependencies: - supports-color - remark-parse@11.0.0(supports-color@7.2.0): + remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-from-markdown: 2.0.3 micromark-util-types: 2.0.2 unified: 11.0.5 transitivePeerDependencies: @@ -9474,7 +9590,7 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.2.3 '@rolldown/binding-win32-x64-msvc': 1.2.3 - router@2.2.0(supports-color@7.2.0): + router@2.2.0: dependencies: debug: 4.4.3(supports-color@7.2.0) depd: 2.0.0 @@ -9521,7 +9637,7 @@ snapshots: semver@7.8.5: {} - send@1.2.1(supports-color@7.2.0): + send@1.2.1: dependencies: debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 @@ -9548,25 +9664,25 @@ snapshots: seroval@1.6.2: {} - serve-static@2.2.1(supports-color@7.2.0): + serve-static@2.2.1: dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 1.2.1(supports-color@7.2.0) + send: 1.2.1 transitivePeerDependencies: - supports-color setprototypeof@1.2.0: {} - shadcn@4.16.2(supports-color@7.2.0)(typescript@6.0.3): + shadcn@4.16.2(typescript@6.0.3): dependencies: - '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/core': 7.29.7 '@babel/parser': 7.29.8 - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) - '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) '@dotenvx/dotenvx': 1.75.1 - '@modelcontextprotocol/sdk': 1.30.0(supports-color@7.2.0)(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.30.0(zod@3.25.76) '@types/validate-npm-package-name': 4.0.2 browserslist: 4.28.7 commander: 14.0.3 @@ -9661,6 +9777,13 @@ snapshots: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) + sonner@2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + dependencies: + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.18 + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -9736,7 +9859,7 @@ snapshots: dependencies: inline-style-parser: 0.2.7 - sumchecker@3.0.1(supports-color@7.2.0): + sumchecker@3.0.1: dependencies: debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: @@ -9854,12 +9977,23 @@ snapshots: '@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/parser': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3) eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color + typescript-eslint@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.8.1(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + typescript@6.0.3: {} typescript@7.0.2: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 2bcade5..ee3c57a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,5 +6,5 @@ allowBuilds: electron-winstaller: true esbuild: true overrides: - "@methanium/ui": "https://git.methanium.net/methanium/ui/releases/download/0.0.28/methanium-ui.tgz" + "@methanium/ui": "https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz" mtp: "https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz" From 73db7e6b2b7541563a81f25a44fa1b2489c01860 Mon Sep 17 00:00:00 2001 From: alois Date: Wed, 12 Aug 2026 15:12:05 +0200 Subject: [PATCH 78/97] Update flake.nix --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 2b8781f..1ed0189 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.11"; - x86_64DebHash = "sha256-E4FGMpCt2ByaN6d+YzglqeA6LbhMOQmPf3UzAj7uZXE="; + x86_64DebHash = "sha256-GtPVJ+WK7np0iGA3OXTWtc7or5biFt2AkchqPRIR9Zg="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From 7b36218ffa600687086065de8b5e8fe24d4bc50a Mon Sep 17 00:00:00 2001 From: Alois Date: Tue, 18 Aug 2026 18:44:45 +0200 Subject: [PATCH 79/97] feat(pwa): add base --- apps/pwa/package.json | 36 + apps/pwa/src/runtime.tsx | 237 ++ apps/pwa/src/serviceWorker.ts | 158 + apps/pwa/src/style.css | 18 + apps/pwa/src/vite.ts | 217 ++ apps/pwa/todo.md | 33 + apps/pwa/tsconfig.json | 23 + apps/pwa/tsconfig.worker.json | 21 + apps/tauri/package.json | 5 - apps/tauri/src-tauri/Cargo.lock | 15 - apps/tauri/src-tauri/Cargo.toml | 3 - apps/tauri/src-tauri/capabilities/mobile.json | 3 - apps/tauri/src-tauri/src/lib.rs | 3 - apps/tauri/src/qrCodeScanner.tsx | 38 - apps/web/package.json | 3 +- apps/web/src/components/navbar.tsx | 1 + .../web/src/components/screens/login/form.tsx | 113 +- apps/web/src/index.tsx | 7 +- apps/web/src/routes/app/layout.tsx | 1 + apps/web/vite.config.ts | 2 + .../LICENSE.spdx | 20 - licenses/THIRD_PARTY_NOTICES.md | 9 - licenses/sbom.cyclonedx.json | 33 +- licenses/third-party-credits.json | 15 +- packages/cache/package.json | 3 +- packages/cache/src/helpers.test.ts | 50 - packages/chat/src/components/input.tsx | 2 - packages/crypto/package.json | 2 +- packages/crypto/src/context.test.ts | 65 - packages/notifications/src/context.tsx | 22 +- packages/onboarding/src/index.tsx | 78 +- packages/onboarding/src/pages/legal.tsx | 85 +- packages/shared/src/data.ts | 13 +- packages/shared/src/features/legal/schema.ts | 5 +- packages/storage/package.json | 4 +- packages/storage/src/browserSecure.ts | 40 + packages/storage/src/context.tsx | 2 +- packages/storage/src/credentials.ts | 68 + packages/storage/src/secure.ts | 17 +- pnpm-lock.yaml | 3150 +++++++++++++++-- 40 files changed, 3856 insertions(+), 764 deletions(-) create mode 100644 apps/pwa/package.json create mode 100644 apps/pwa/src/runtime.tsx create mode 100644 apps/pwa/src/serviceWorker.ts create mode 100644 apps/pwa/src/style.css create mode 100644 apps/pwa/src/vite.ts create mode 100644 apps/pwa/todo.md create mode 100644 apps/pwa/tsconfig.json create mode 100644 apps/pwa/tsconfig.worker.json delete mode 100644 apps/tauri/src/qrCodeScanner.tsx delete mode 100644 licenses/@tauri-apps_plugin-barcode-scanner@2.4.5/LICENSE.spdx delete mode 100644 packages/cache/src/helpers.test.ts delete mode 100644 packages/crypto/src/context.test.ts create mode 100644 packages/storage/src/browserSecure.ts create mode 100644 packages/storage/src/credentials.ts diff --git a/apps/pwa/package.json b/apps/pwa/package.json new file mode 100644 index 0000000..39c4ec5 --- /dev/null +++ b/apps/pwa/package.json @@ -0,0 +1,36 @@ +{ + "name": "@tensamin/pwa", + "private": true, + "version": "0.0.0", + "type": "module", + "exports": { + "./vite": "./src/vite.ts", + "./runtime": "./src/runtime.tsx" + }, + "scripts": { + "format": "pnpm exec prettier --write .", + "lint": "eslint src", + "build": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.worker.json --noEmit" + }, + "dependencies": { + "@methanium/ui": "*", + "@tauri-apps/api": "^2.11.1", + "@tensamin/crypto": "workspace:*", + "@tensamin/shared": "workspace:*", + "@tensamin/storage": "workspace:*", + "mtp": "*", + "react": "^19.2.8", + "sonner": "^2.0.7", + "vite-plugin-pwa": "^1.1.0", + "workbox-core": "^7.3.0", + "workbox-precaching": "^7.3.0", + "workbox-routing": "^7.3.0", + "workbox-strategies": "^7.3.0" + }, + "devDependencies": { + "@types/node": "^26.1.2", + "@types/react": "^19.2.18", + "typescript": "~6.0.3", + "vite": "^8.2.1" + } +} diff --git a/apps/pwa/src/runtime.tsx b/apps/pwa/src/runtime.tsx new file mode 100644 index 0000000..d7917cc --- /dev/null +++ b/apps/pwa/src/runtime.tsx @@ -0,0 +1,237 @@ +import { useEffect, useState } from "react"; +import { toast } from "sonner"; + +import { setDatabaseEntry } from "@tensamin/shared/indexedDb"; +import { isTauri } from "@tauri-apps/api/core"; + +import "./style.css"; + +type BeforeInstallPromptEvent = Event & { + prompt: () => Promise; + userChoice: Promise<{ outcome: "accepted" | "dismissed" }>; +}; + +const launchedFiles: File[] = []; +const fileListeners = new Set<(file: File) => void>(); + +function emitLaunchedFile(file: File) { + if (fileListeners.size === 0) launchedFiles.push(file); + else for (const listener of fileListeners) listener(file); +} + +export function subscribeTuFileLaunch(listener: (file: File) => void) { + fileListeners.add(listener); + for (const file of launchedFiles.splice(0)) listener(file); + return () => { + fileListeners.delete(listener); + }; +} + +function isStandalone() { + return ( + window.matchMedia("(display-mode: standalone)").matches || + (navigator as Navigator & { standalone?: boolean }).standalone === true + ); +} + +function applicationServerKey(value: string) { + const normalized = value.replace(/-/g, "+").replace(/_/g, "/"); + const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "="); + return Uint8Array.from(atob(padded), (character) => character.charCodeAt(0)); +} + +async function enablePush() { + if (!("Notification" in window)) + throw new Error("Notifications are not supported by this browser."); + const permission = await Notification.requestPermission(); + if (permission !== "granted") + throw new Error("Notification permission was not granted."); + + const publicKey = import.meta.env.VITE_WEB_PUSH_PUBLIC_KEY; + if ( + !publicKey || + !("serviceWorker" in navigator) || + !("PushManager" in window) + ) { + return; + } + const registration = await navigator.serviceWorker.ready; + const subscription = + (await registration.pushManager.getSubscription()) ?? + (await registration.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: applicationServerKey(publicKey), + })); + await setDatabaseEntry("keys", "push-subscription", subscription.toJSON()); +} + +export default function PwaRuntime() { + const [installPrompt, setInstallPrompt] = + useState(null); + + useEffect(() => { + if ( + isTauri() || + !("serviceWorker" in navigator) || + !["http:", "https:"].includes(window.location.protocol) + ) { + return; + } + let reloading = false; + const handleControllerChange = () => { + if (reloading) return; + reloading = true; + // A newly activated service worker must reload the document it controls. + // eslint-disable-next-line tensamin/no-window-location-reload + window.location.reload(); + }; + navigator.serviceWorker.addEventListener( + "controllerchange", + handleControllerChange, + ); + void navigator.serviceWorker + .register( + import.meta.env.DEV ? "/dev-sw.js?dev-sw" : "/serviceWorker.js", + { + type: "module", + }, + ) + .then((registration) => { + const watchWorker = (worker: ServiceWorker) => { + worker.addEventListener("statechange", () => { + if (worker.state !== "installed") return; + if (!navigator.serviceWorker.controller) { + toast.success("Tensamin is ready for offline startup"); + return; + } + toast("A Tensamin update is ready", { + duration: Infinity, + action: { + label: "Update", + onClick: () => worker.postMessage({ type: "SKIP_WAITING" }), + }, + }); + }); + }; + if (registration.installing) watchWorker(registration.installing); + registration.addEventListener("updatefound", () => { + if (registration.installing) watchWorker(registration.installing); + }); + }) + .catch((error: unknown) => { + console.error("Failed to register the Tensamin service worker", error); + }); + return () => { + navigator.serviceWorker.removeEventListener( + "controllerchange", + handleControllerChange, + ); + }; + }, []); + + useEffect(() => { + const handleInstallPrompt = (event: Event) => { + event.preventDefault(); + setInstallPrompt(event as BeforeInstallPromptEvent); + }; + window.addEventListener("beforeinstallprompt", handleInstallPrompt); + return () => + window.removeEventListener("beforeinstallprompt", handleInstallPrompt); + }, []); + + useEffect(() => { + const launchQueue = ( + window as Window & { + launchQueue?: { + setConsumer: ( + consumer: (params: { + files?: Array<{ getFile: () => Promise }>; + }) => void, + ) => void; + }; + } + ).launchQueue; + launchQueue?.setConsumer((params) => { + for (const handle of params.files ?? []) { + void handle.getFile().then(emitLaunchedFile); + } + }); + }, []); + + useEffect(() => { + if (!installPrompt) return; + toast("Install Tensamin for a native app experience", { + duration: Infinity, + action: { + label: "Install", + onClick: () => { + void installPrompt.prompt().then(() => installPrompt.userChoice); + setInstallPrompt(null); + }, + }, + }); + }, [installPrompt]); + + useEffect(() => { + const isAppleMobile = /iPad|iPhone|iPod/.test(navigator.userAgent); + if ( + isTauri() || + !isAppleMobile || + isStandalone() || + localStorage.getItem("pwa-ios-install-hint") + ) { + return; + } + localStorage.setItem("pwa-ios-install-hint", "shown"); + toast( + "Install Tensamin from Safari's Share menu to enable background notifications.", + { + duration: 12_000, + }, + ); + }, []); + + useEffect(() => { + if ( + !isStandalone() || + !("Notification" in window) || + Notification.permission !== "default" || + localStorage.getItem("pwa-push-hint") + ) { + return; + } + localStorage.setItem("pwa-push-hint", "shown"); + toast("Enable message notifications", { + duration: Infinity, + action: { + label: "Enable", + onClick: () => { + void enablePush() + .then(() => toast.success("Notifications enabled")) + .catch((error: unknown) => + toast.error( + error instanceof Error + ? error.message + : "Could not enable notifications", + ), + ); + }, + }, + }); + }, []); + + useEffect(() => { + if ( + isStandalone() && + "Notification" in window && + Notification.permission === "granted" && + import.meta.env.VITE_WEB_PUSH_PUBLIC_KEY + ) { + void enablePush().catch((error: unknown) => { + console.error("Failed to refresh the Web Push subscription", error); + }); + } + }, []); + + return null; +} diff --git a/apps/pwa/src/serviceWorker.ts b/apps/pwa/src/serviceWorker.ts new file mode 100644 index 0000000..de341bb --- /dev/null +++ b/apps/pwa/src/serviceWorker.ts @@ -0,0 +1,158 @@ +/// + +import { base64ToBytes } from "mtp"; +import { clientsClaim } from "workbox-core"; +import { cleanupOutdatedCaches, precacheAndRoute } from "workbox-precaching"; +import { NavigationRoute, registerRoute } from "workbox-routing"; +import { createHandlerBoundToURL } from "workbox-precaching"; +import { CacheFirst } from "workbox-strategies"; + +import { decryptChatText, unwrapChatSecret } from "@tensamin/crypto/chatSecret"; +import { loadSecureBrowserValue } from "@tensamin/storage/browserSecure"; + +declare let self: ServiceWorkerGlobalScope; + +type PushPayload = { + version: 1; + senderId: number; + sender: string; + avatar?: string; + message: { content: string }; + secret: { + chatId: string; + secretId: string; + version: number; + encryptedSecret: string; + kemCiphertext: string; + wrappingScheme: string; + }; +}; + +function isPushPayload(value: unknown): value is PushPayload { + if (!value || typeof value !== "object") return false; + const payload = value as Partial; + const message = payload.message as + Partial | undefined; + const secret = payload.secret as Partial | undefined; + return ( + payload.version === 1 && + typeof payload.senderId === "number" && + Number.isSafeInteger(payload.senderId) && + payload.senderId > 0 && + typeof payload.sender === "string" && + typeof message?.content === "string" && + typeof secret?.chatId === "string" && + typeof secret.secretId === "string" && + typeof secret.version === "number" && + typeof secret.encryptedSecret === "string" && + typeof secret.kemCiphertext === "string" && + typeof secret.wrappingScheme === "string" + ); +} + +async function decryptPush(payload: PushPayload) { + const keyring = await loadSecureBrowserValue("mtp_keyring"); + if (!keyring) throw new Error("MTP credentials are unavailable."); + const chatSecret = await unwrapChatSecret({ + encryptedSecret: base64ToBytes(payload.secret.encryptedSecret), + kemCiphertext: base64ToBytes(payload.secret.kemCiphertext), + keyring, + chatId: payload.secret.chatId, + secretId: payload.secret.secretId, + version: payload.secret.version, + wrappingScheme: payload.secret.wrappingScheme, + }); + try { + return await decryptChatText(chatSecret, payload.message.content); + } finally { + chatSecret.fill(0); + } +} + +clientsClaim(); +cleanupOutdatedCaches(); +const precacheManifest = self.__WB_MANIFEST; +precacheAndRoute(precacheManifest); + +if ( + precacheManifest.some((entry) => + (typeof entry === "string" ? entry : entry.url).endsWith("index.html"), + ) +) { + registerRoute( + new NavigationRoute(createHandlerBoundToURL("index.html"), { + denylist: [/^\/api\//], + }), + ); +} +registerRoute( + ({ request, url }) => + url.origin === self.location.origin && + ["font", "image", "style"].includes(request.destination), + new CacheFirst({ cacheName: "tensamin-static-v1" }), +); + +self.addEventListener("push", (event) => { + event.waitUntil( + (async () => { + let payload: PushPayload | undefined; + try { + const value = event.data?.json() as unknown; + if (isPushPayload(value)) payload = value; + } catch { + // The generic notification below is safe for malformed payloads. + } + + let body = "Open Tensamin to view the encrypted message."; + if (payload) { + try { + body = await decryptPush(payload); + } catch { + // Do not leak credential or decryption failures in the notification. + } + } + + await self.registration.showNotification(payload?.sender ?? "Tensamin", { + body, + icon: payload?.avatar || "./icons/icon-192.png", + badge: "./icons/notification-badge.png", + tag: payload ? `message-${payload.senderId}` : "message", + data: { url: payload ? `/chat?id=${payload.senderId}` : "/" }, + }); + + const navigatorWithBadge = self.navigator as WorkerNavigator & { + setAppBadge?: (contents?: number) => Promise; + }; + await navigatorWithBadge.setAppBadge?.().catch(() => undefined); + })(), + ); +}); + +self.addEventListener("notificationclick", (event) => { + event.notification.close(); + event.waitUntil( + (async () => { + const target = new URL( + String( + (event.notification.data as { url?: string } | undefined)?.url ?? "/", + ), + self.location.origin, + ); + const windows = await self.clients.matchAll({ + type: "window", + includeUncontrolled: true, + }); + for (const client of windows) { + if ("navigate" in client) await client.navigate(target.href); + return client.focus(); + } + return self.clients.openWindow(target.href); + })(), + ); +}); + +self.addEventListener("message", (event) => { + if ((event.data as { type?: string } | undefined)?.type === "SKIP_WAITING") { + void self.skipWaiting(); + } +}); diff --git a/apps/pwa/src/style.css b/apps/pwa/src/style.css new file mode 100644 index 0000000..213d773 --- /dev/null +++ b/apps/pwa/src/style.css @@ -0,0 +1,18 @@ +@media (display-mode: standalone), (display-mode: fullscreen) { + [data-pwa-root] { + padding-top: env(safe-area-inset-top, 0px); + padding-right: env(safe-area-inset-right, 0px); + padding-left: env(safe-area-inset-left, 0px); + } +} + +@media (display-mode: window-controls-overlay) and (min-width: 768px) { + [data-pwa-navbar] { + min-height: env(titlebar-area-height, 3.375rem); + padding-left: max(1px, env(titlebar-area-x, 0px)); + padding-right: max( + 0px, + calc(100vw - env(titlebar-area-x, 0px) - env(titlebar-area-width, 100vw)) + ); + } +} diff --git a/apps/pwa/src/vite.ts b/apps/pwa/src/vite.ts new file mode 100644 index 0000000..908a3d2 --- /dev/null +++ b/apps/pwa/src/vite.ts @@ -0,0 +1,217 @@ +import { readFileSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +import type { Plugin } from "vite"; +import { VitePWA } from "vite-plugin-pwa"; + +const pwaDirectory = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const tauriIcons = resolve(pwaDirectory, "../tauri/src-tauri/icons"); +const androidResources = resolve( + pwaDirectory, + "../tauri/src-tauri/gen/android/app/src/main/res", +); + +function emitIcons(): Plugin { + const icons = [ + { + fileName: "icons/icon-180.png", + source: resolve(tauriIcons, "ios/AppIcon-60x60@3x.png"), + }, + { + fileName: "icons/icon-192.png", + source: resolve(androidResources, "mipmap-xxxhdpi/ic_launcher.png"), + }, + { + fileName: "icons/icon-96.png", + source: resolve(androidResources, "mipmap-xhdpi/ic_launcher.png"), + }, + { + fileName: "icons/icon-512.png", + source: resolve(tauriIcons, "icon.png"), + }, + { + fileName: "icons/icon-maskable-512.png", + source: resolve(tauriIcons, "icon.png"), + }, + { + fileName: "icons/icon-monochrome-432.png", + source: resolve( + androidResources, + "mipmap-xxxhdpi/ic_launcher_monochrome.png", + ), + }, + { + fileName: "icons/notification-badge.png", + source: resolve(androidResources, "drawable/ic_notification_small.png"), + }, + ]; + + return { + name: "tensamin-pwa-icons", + configureServer(server) { + server.middlewares.use((request, response, next) => { + const pathname = request.url + ? new URL(request.url, "http://localhost").pathname.slice(1) + : ""; + const icon = icons.find(({ fileName }) => fileName === pathname); + if (!icon) { + next(); + return; + } + response.statusCode = 200; + response.setHeader("Content-Type", "image/png"); + response.setHeader("Cache-Control", "no-cache"); + response.end(readFileSync(icon.source)); + }); + }, + generateBundle() { + for (const icon of icons) { + this.emitFile({ + type: "asset", + fileName: icon.fileName, + source: readFileSync(icon.source), + }); + } + }, + transformIndexHtml: { + order: "post", + handler() { + return [ + { + tag: "link", + attrs: { + rel: "apple-touch-icon", + sizes: "180x180", + href: "./icons/icon-180.png", + }, + injectTo: "head", + }, + { + tag: "meta", + attrs: { name: "apple-mobile-web-app-capable", content: "yes" }, + injectTo: "head", + }, + { + tag: "meta", + attrs: { + name: "apple-mobile-web-app-status-bar-style", + content: "black-translucent", + }, + injectTo: "head", + }, + { + tag: "meta", + attrs: { + name: "apple-mobile-web-app-title", + content: "Tensamin", + }, + injectTo: "head", + }, + { + tag: "meta", + attrs: { name: "theme-color", content: "#006a67" }, + injectTo: "head", + }, + ]; + }, + }, + }; +} + +export function tensaminPwa(): Plugin[] { + return [ + emitIcons(), + ...VitePWA({ + strategies: "injectManifest", + srcDir: resolve(pwaDirectory, "src"), + filename: "serviceWorker.ts", + injectRegister: null, + registerType: "prompt", + manifestFilename: "manifest.json", + includeAssets: ["favicon.ico", "icons/*.png"], + manifest: { + id: "/", + name: "Tensamin", + short_name: "Tensamin", + description: "Private messaging and calls with Tensamin.", + start_url: "/", + scope: "/", + display: "standalone", + display_override: ["window-controls-overlay", "standalone"], + background_color: "#001f1e", + theme_color: "#006a67", + categories: ["social", "communication"], + orientation: "any", + launch_handler: { client_mode: "focus-existing" }, + icons: [ + { + src: "icons/icon-192.png", + sizes: "192x192", + type: "image/png", + purpose: "any", + }, + { + src: "icons/icon-512.png", + sizes: "512x512", + type: "image/png", + purpose: "any", + }, + { + src: "icons/icon-maskable-512.png", + sizes: "512x512", + type: "image/png", + purpose: "maskable", + }, + { + src: "icons/icon-monochrome-432.png", + sizes: "432x432", + type: "image/png", + purpose: "monochrome", + }, + ], + shortcuts: [ + { + name: "Chats", + short_name: "Chats", + url: "/", + icons: [ + { + src: "icons/icon-96.png", + sizes: "96x96", + type: "image/png", + }, + ], + }, + { + name: "Settings", + short_name: "Settings", + url: "/settings", + icons: [ + { + src: "icons/icon-96.png", + sizes: "96x96", + type: "image/png", + }, + ], + }, + ], + file_handlers: [ + { + action: "/login", + accept: { "application/x-tensamin-user": [".tu"] }, + }, + ], + }, + injectManifest: { + globPatterns: ["**/*.{js,css,html,ico,png,svg,woff2,wasm,mp3,wav}"], + globIgnores: ["assets/v2/**"], + maximumFileSizeToCacheInBytes: 15 * 1024 * 1024, + }, + devOptions: { + enabled: true, + type: "module", + }, + }), + ]; +} diff --git a/apps/pwa/todo.md b/apps/pwa/todo.md new file mode 100644 index 0000000..b5b2055 --- /dev/null +++ b/apps/pwa/todo.md @@ -0,0 +1,33 @@ +# Web Push Backend TODO + +The client can subscribe and decrypt version 1 push payloads, but reliable delivery requires backend support. + +- Generate and securely store a VAPID key pair. Expose only the public key to the web build as `VITE_WEB_PUSH_PUBLIC_KEY`. +- Add authenticated MTP requests for registering, replacing, and deleting a browser `PushSubscription` per user and installation. +- Persist the endpoint, `p256dh`, `auth`, expiration time, stable installation ID, and last-seen time. +- Remove subscriptions when a push service returns HTTP 404 or 410 and rate-limit registrations per user. +- Send pushes when an encrypted live message cannot be delivered to an active browser client. Define duplicate suppression for clients that receive both MTP and Web Push. +- Keep the JSON payload within push-provider limits and use this version 1 shape: + +```json +{ + "version": 1, + "senderId": 123, + "sender": "Display name", + "avatar": "https://optional.example/avatar", + "message": { "content": "base64 encrypted message content" }, + "secret": { + "chatId": "123:456", + "secretId": "chat:123:456:main", + "version": 1, + "encryptedSecret": "base64 wrapped chat secret", + "kemCiphertext": "base64 KEM ciphertext", + "wrappingScheme": "mtp-chat-secret-kem-chacha20poly1305-hkdf-sha256-v1" + } +} +``` + +- Ensure the wrapped secret is intended for the receiving user's MTP keyring. The server must never receive plaintext message content or plaintext chat secrets. +- Decide how edits, deletions, reactions, calls, read states, and per-chat notification cancellation map to push events. +- Add subscription rotation handling and unregister subscriptions when a user logs out or clears application data. +- Configure production HTTPS, SPA route fallback, `application/manifest+json` for `manifest.json`, and `Cache-Control: no-cache` for the service worker. diff --git a/apps/pwa/tsconfig.json b/apps/pwa/tsconfig.json new file mode 100644 index 0000000..1e7cfde --- /dev/null +++ b/apps/pwa/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client", "vite-plugin-pwa/client", "node"], + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/runtime.tsx", "src/vite.ts"] +} diff --git a/apps/pwa/tsconfig.worker.json b/apps/pwa/tsconfig.worker.json new file mode 100644 index 0000000..a478894 --- /dev/null +++ b/apps/pwa/tsconfig.worker.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "lib": ["ES2022", "WebWorker"], + "types": ["vite-plugin-pwa/client"], + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/serviceWorker.ts"] +} diff --git a/apps/tauri/package.json b/apps/tauri/package.json index 8eab808..36937be 100644 --- a/apps/tauri/package.json +++ b/apps/tauri/package.json @@ -7,10 +7,6 @@ "./deeplinkHandler": { "types": "./src/deeplinkHandler.tsx", "default": "./src/deeplinkHandler.tsx" - }, - "./qrCodeScanner": { - "types": "./src/qrCodeScanner.tsx", - "default": "./src/qrCodeScanner.tsx" } }, "scripts": { @@ -28,7 +24,6 @@ "dependencies": { "@methanium/ui": "*", "@tauri-apps/api": "^2.11.1", - "@tauri-apps/plugin-barcode-scanner": "~2.4.5", "@tauri-apps/plugin-deep-link": "~2.4.9", "@tensamin/shared": "workspace:*", "react": "^19.2.8", diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index 7a30247..b1b1c0b 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -5035,20 +5035,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "tauri-plugin-barcode-scanner" -version = "2.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b68f0e3782b61a6e16a67380be40226e2b7233f3e36dadf6e5d03f07d2e7b3" -dependencies = [ - "log", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.19", -] - [[package]] name = "tauri-plugin-deep-link" version = "2.4.9" @@ -5309,7 +5295,6 @@ dependencies = [ "serde_json", "tauri", "tauri-build", - "tauri-plugin-barcode-scanner", "tauri-plugin-deep-link", "tauri-plugin-log", "tauri-plugin-notification", diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index 3b7e6b5..08a66d5 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -39,9 +39,6 @@ default-features = true [target.'cfg(target_os = "android")'.dependencies] jni = "0.22" -[target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] -tauri-plugin-barcode-scanner = "2" - [patch.crates-io.tauri] git = "https://github.com/tauri-apps/tauri" rev = "4af26a3f7f8b692d62cca549bbacd93f5ce90b41" diff --git a/apps/tauri/src-tauri/capabilities/mobile.json b/apps/tauri/src-tauri/capabilities/mobile.json index 7121f98..91f1d4e 100644 --- a/apps/tauri/src-tauri/capabilities/mobile.json +++ b/apps/tauri/src-tauri/capabilities/mobile.json @@ -5,9 +5,6 @@ "permissions": [ "core:event:default", "deep-link:default", - "barcode-scanner:default", - "barcode-scanner:allow-scan", - "barcode-scanner:allow-cancel", "notification:default", "log:default" ] diff --git a/apps/tauri/src-tauri/src/lib.rs b/apps/tauri/src-tauri/src/lib.rs index e81a830..6636682 100644 --- a/apps/tauri/src-tauri/src/lib.rs +++ b/apps/tauri/src-tauri/src/lib.rs @@ -15,9 +15,6 @@ pub fn run() { .plugin(tauri_plugin_deep_link::init()) .plugin(tauri_plugin_opener::init()); - #[cfg(any(target_os = "ios", target_os = "android"))] - let builder = builder.plugin(tauri_plugin_barcode_scanner::init()); - let app = builder .invoke_handler(tauri::generate_handler![ accessibility_backend::accessibility_get_initial_scale, diff --git a/apps/tauri/src/qrCodeScanner.tsx b/apps/tauri/src/qrCodeScanner.tsx deleted file mode 100644 index fa3f3c7..0000000 --- a/apps/tauri/src/qrCodeScanner.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { - scan, - Format, - requestPermissions, -} from "@tauri-apps/plugin-barcode-scanner"; -import { Button } from "@methanium/ui"; - -import { toast } from "@tensamin/shared/log"; - -export default function QrCodeScanner({ - onData, -}: { - onData: (data: string) => void; -}) { - return ( - - ); -} diff --git a/apps/web/package.json b/apps/web/package.json index 15a4c00..f608fcb 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -8,7 +8,7 @@ "lint": "eslint src", "dev": "vite", "test": "vitest run --passWithNoTests", - "build": "pnpm run test && tsc -b && vite build", + "build": "pnpm --filter @tensamin/pwa build && pnpm run test && tsc -b && vite build", "preview": "cd dist && nix-shell -p python3 --run 'python3 -m http.server 3000' && cd .." }, "dependencies": { @@ -18,6 +18,7 @@ "@tanstack/react-router": "^1.170.21", "@tanstack/react-virtual": "^3.14.9", "@tauri-apps/api": "^2.11.1", + "@tensamin/pwa": "workspace:*", "@tensamin/cache": "workspace:*", "@tensamin/call": "workspace:*", "@tensamin/chat": "workspace:*", diff --git a/apps/web/src/components/navbar.tsx b/apps/web/src/components/navbar.tsx index 2f1c115..122f188 100644 --- a/apps/web/src/components/navbar.tsx +++ b/apps/web/src/components/navbar.tsx @@ -52,6 +52,7 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) { return (
    diff --git a/apps/web/src/components/screens/login/form.tsx b/apps/web/src/components/screens/login/form.tsx index 72db8f7..c9fa041 100644 --- a/apps/web/src/components/screens/login/form.tsx +++ b/apps/web/src/components/screens/login/form.tsx @@ -13,8 +13,11 @@ import { useState, } from "react"; import { z } from "zod"; -import { invoke, isTauri } from "@tauri-apps/api/core"; -import QrCodeScanner from "@tensamin/tauri/qrCodeScanner"; +import { subscribeTuFileLaunch } from "@tensamin/pwa/runtime"; +import { + parseTuFileContent, + persistMtpCredentials, +} from "@tensamin/storage/credentials"; import { useNavigate } from "@tanstack/react-router"; const fetchedUser = z.object({ @@ -35,50 +38,6 @@ const formSchema = z.object({ mtp_keyring: z.string().min(1).max(92), }); -/** - * Parses a .tu file payload into credentials. - * @param rawFileContent UTF-8 file content from an uploaded .tu file. - * @returns Parsed user id and private key credentials. - */ -function parseTuFileContent(rawFileContent: string): { - userId: number; - privateKey: string; - domain: string | null; -} { - if (rawFileContent.trim().length === 0) { - throw new Error("File is empty"); - } else if (!rawFileContent.includes("::")) { - throw new Error("Invalid file"); - } else if (rawFileContent.split("::").length !== 2) { - throw new Error("Invalid file"); - } - - const left = rawFileContent.split("::")[0]; - const right = rawFileContent.split("::")[1]; - - if (left.length === 0) { - throw new Error("Invalid file"); - } else if (right.length === 0) { - throw new Error("Invalid file"); - } else if (isNaN(Number(left)) && !left.includes("@")) { - throw new Error("Invalid file"); - } - - const [userIdString, privateKeyValue] = rawFileContent.split("::"); - const privateKey = privateKeyValue.trim(); - const userId = isNaN(Number(userIdString)) - ? Number(userIdString.split("@")[0]) - : Number(userIdString); - - const domain = userIdString.includes("@") ? userIdString.split("@")[1] : null; - - if (!userId || !privateKey) { - throw new Error("Invalid file"); - } - - return { userId, privateKey, domain }; -} - export default function Form() { const isMobile = useIsMobile(); const uploadRef = useRef(null); @@ -92,27 +51,12 @@ export default function Form() { if (loginPendingRef.current) return false; loginPendingRef.current = true; try { - if (domain) await save("omega_url", `https://${domain}/`); - if (isTauri()) { - const [omegaUrl, forcedOmikronUrl, forcedOmikronPublicKey] = - await Promise.all([ - domain ? `https://${domain}/` : load("omega_url"), - load("forced_omikron_url"), - load("forced_omikron_public_key"), - ]); - await invoke("mtp_store_credentials", { - config: { - userId, - keyring: privateKey, - omegaUrl, - forcedOmikronUrl, - forcedOmikronPublicKey, - }, - }); - } - await save("mtp_keyring", privateKey, { secure: true }); - await save("session_id", Date.now()); - await save("user_id", userId); + await persistMtpCredentials({ + storage: { load, save }, + userId, + keyring: privateKey, + domain, + }); await navigate({ to: "/", replace: true }); return true; } finally { @@ -143,6 +87,11 @@ export default function Form() { [persistLogin], ); + useEffect( + () => subscribeTuFileLaunch(processDroppedFile), + [processDroppedFile], + ); + // Handle .tu files const handleFileInputChange = useCallback( async (event: ChangeEvent): Promise => { @@ -281,32 +230,10 @@ export default function Form() { return (
    - {isTauri() && isMobile ? ( - <> - { - if (!data.startsWith("tensamin://tu::")) { - toast("error", "Invalid QR code"); - return; - } - - const decoded = data.replace("tensamin://tu::", ""); - - try { - const { userId, privateKey, domain } = - parseTuFileContent(decoded); - - await persistLogin(userId, privateKey, domain); - } catch (error) { - log(0, "login", "red", error); - toast("error", "Failed to parse QR code data"); - } - }} - /> - - + {isMobile ? ( + ) : (
    uploadRef.current?.click()} diff --git a/apps/web/src/index.tsx b/apps/web/src/index.tsx index 303cb2a..460e92b 100644 --- a/apps/web/src/index.tsx +++ b/apps/web/src/index.tsx @@ -29,6 +29,7 @@ import { Provider as MTPProvider } from "@tensamin/mtp"; import UserProvider from "@tensamin/user/context"; import DeeplinkContext, { useDeeplinks } from "@tensamin/tauri/deeplinkHandler"; import NotificationsProvider from "@tensamin/notifications/context"; +import PwaRuntime from "@tensamin/pwa/runtime"; import TAuthWrapper from "@tensamin/tauth/context"; @@ -253,10 +254,14 @@ function RootShell() { parentThemeStorageKey={null} designStorageKey={null} > -
    +
    + diff --git a/apps/web/src/routes/app/layout.tsx b/apps/web/src/routes/app/layout.tsx index 9a46805..9f165b4 100644 --- a/apps/web/src/routes/app/layout.tsx +++ b/apps/web/src/routes/app/layout.tsx @@ -19,6 +19,7 @@ export default function Layout({ children }: { children: ReactNode }) {
    Tauri is a rust project that enables developers to make secure -and small desktop applications using a web frontend. - -PackageComment: The package includes the following libraries; see -Relationship information. - -Created: 2019-05-20T09:00:00Z -PackageDownloadLocation: git://github.com/tauri-apps/tauri -PackageDownloadLocation: git+https://github.com/tauri-apps/tauri.git -PackageDownloadLocation: git+ssh://github.com/tauri-apps/tauri.git -Creator: Person: Daniel Thompson-Yvetot \ No newline at end of file diff --git a/licenses/THIRD_PARTY_NOTICES.md b/licenses/THIRD_PARTY_NOTICES.md index 2094186..3d61ec4 100644 --- a/licenses/THIRD_PARTY_NOTICES.md +++ b/licenses/THIRD_PARTY_NOTICES.md @@ -117,15 +117,6 @@ Generated from pnpm-lock.yaml and installed packages in workspace node_modules f - Folder: `licenses/@tauri-apps_cli@2.11.4` - Source package dir: `apps/tauri/node_modules/@tauri-apps/cli` -## @tauri-apps/plugin-barcode-scanner@2.4.5 - -- License: MIT OR Apache-2.0 -- Repository: https://github.com/tauri-apps/plugins-workspace -- Description: Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS -- Included files: LICENSE.spdx -- Folder: `licenses/@tauri-apps_plugin-barcode-scanner@2.4.5` -- Source package dir: `apps/tauri/node_modules/@tauri-apps/plugin-barcode-scanner` - ## @tauri-apps/plugin-deep-link@2.4.9 - License: MIT OR Apache-2.0 diff --git a/licenses/sbom.cyclonedx.json b/licenses/sbom.cyclonedx.json index ebb655c..2fca23f 100644 --- a/licenses/sbom.cyclonedx.json +++ b/licenses/sbom.cyclonedx.json @@ -414,37 +414,6 @@ } ] }, - { - "type": "library", - "bomRef": "pkg:npm/%40tauri-apps/plugin-barcode-scanner@2.4.5", - "name": "@tauri-apps/plugin-barcode-scanner", - "version": "2.4.5", - "purl": "pkg:npm/%40tauri-apps/plugin-barcode-scanner@2.4.5", - "description": "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS", - "licenses": [ - { - "license": { - "name": "MIT OR Apache-2.0" - } - } - ], - "externalReferences": [ - { - "type": "vcs", - "url": "https://github.com/tauri-apps/plugins-workspace" - } - ], - "properties": [ - { - "name": "local:licenseFolder", - "value": "licenses/@tauri-apps_plugin-barcode-scanner@2.4.5" - }, - { - "name": "local:sourcePackageDir", - "value": "apps/tauri/node_modules/@tauri-apps/plugin-barcode-scanner" - } - ] - }, { "type": "library", "bomRef": "pkg:npm/%40tauri-apps/plugin-deep-link@2.4.9", @@ -1754,4 +1723,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/licenses/third-party-credits.json b/licenses/third-party-credits.json index 5ea2d3d..6188b40 100644 --- a/licenses/third-party-credits.json +++ b/licenses/third-party-credits.json @@ -160,19 +160,6 @@ "licenseFolder": "licenses/@tauri-apps_cli@2.11.4", "sourcePackageDir": "apps/tauri/node_modules/@tauri-apps/cli" }, - { - "name": "@tauri-apps/plugin-barcode-scanner", - "version": "2.4.5", - "license": "MIT OR Apache-2.0", - "homepage": null, - "repository": "https://github.com/tauri-apps/plugins-workspace", - "description": "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS", - "files": [ - "LICENSE.spdx" - ], - "licenseFolder": "licenses/@tauri-apps_plugin-barcode-scanner@2.4.5", - "sourcePackageDir": "apps/tauri/node_modules/@tauri-apps/plugin-barcode-scanner" - }, { "name": "@tauri-apps/plugin-deep-link", "version": "2.4.9", @@ -678,4 +665,4 @@ "sourcePackageDir": "packages/call/node_modules/zustand" } ] -} \ No newline at end of file +} diff --git a/packages/cache/package.json b/packages/cache/package.json index f8ef91b..2a69aa9 100644 --- a/packages/cache/package.json +++ b/packages/cache/package.json @@ -12,8 +12,7 @@ "scripts": { "format": "pnpm exec prettier --write .", "lint": "eslint src", - "test": "vitest run", - "build": "pnpm run test && tsc -p tsconfig.json --noEmit" + "build": "tsc -p tsconfig.json --noEmit" }, "dependencies": { "@tensamin/mtp": "workspace:*", diff --git a/packages/cache/src/helpers.test.ts b/packages/cache/src/helpers.test.ts deleted file mode 100644 index 035c285..0000000 --- a/packages/cache/src/helpers.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { - replaceConversation, - selectConversationWindows, - trimMessages, -} from "./helpers"; -import type { CachedMessage, ConversationWindow } from "./schemas"; - -const message = (SendTime: number): CachedMessage => ({ - SenderId: 1, - SendTime, - Content: "Y2lwaGVydGV4dA==", - MessageState: "received", -}); -const window = (UserId: number, LastMessageAt: number): ConversationWindow => ({ - UserId, - LastMessageAt, - Messages: [], -}); - -describe("conversation cache helpers", () => { - it("selects the five most recent windows", () => { - const selected = selectConversationWindows( - [ - window(1, 1), - window(2, 6), - window(3, 3), - window(4, 4), - window(5, 5), - window(6, 2), - ], - 5, - ); - expect(selected.map(({ UserId }) => UserId)).toEqual([2, 5, 4, 3, 6]); - }); - - it("replaces only the matching conversation", () => { - expect( - replaceConversation([window(1, 1), window(2, 2)], window(1, 9)), - ).toEqual([window(1, 9), window(2, 2)]); - }); - - it("retains the newest messages in chronological order", () => { - expect( - trimMessages([message(2), message(3), message(1)], 2).map( - (item) => item.SendTime, - ), - ).toEqual([2, 3]); - }); -}); diff --git a/packages/chat/src/components/input.tsx b/packages/chat/src/components/input.tsx index e7a8d6e..469c28a 100644 --- a/packages/chat/src/components/input.tsx +++ b/packages/chat/src/components/input.tsx @@ -4,8 +4,6 @@ import { CardHeader, Drawer, DrawerContent, - DrawerDescription, - DrawerTitle, DrawerTrigger, Popover, PopoverContent, diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 6477f6e..62580df 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -12,7 +12,7 @@ "format": "pnpm exec prettier --write .", "lint": "eslint src", "test": "vitest run", - "build": "pnpm run test && tsc -p tsconfig.json --noEmit" + "build": "tsc -p tsconfig.json --noEmit" }, "dependencies": { "react": "^19.2.8", diff --git a/packages/crypto/src/context.test.ts b/packages/crypto/src/context.test.ts deleted file mode 100644 index e6c2178..0000000 --- a/packages/crypto/src/context.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { describe, expect, test, vi } from "vitest"; - -vi.mock("mtp", () => ({ - crypto: {}, -})); - -import { createCryptoActions } from "./context"; - -/** - * Creates a rejected API getter used to verify initialization guards. - * @returns Null API reference. - */ -function getUninitializedApi(): null { - return null; -} - -describe("createCryptoActions", () => { - const textEncoder = new TextEncoder(); - const textDecoder = new TextDecoder(); - - test("throws when API is not initialized", async () => { - const actions = createCryptoActions(getUninitializedApi); - - let failed = false; - try { - await actions.encrypt("ab", new TextEncoder().encode("plain")); - } catch (error) { - failed = (error as Error).message.includes("API not initialized"); - } - - expect(failed).toBe(true); - }); - - test("delegates encrypt/decrypt/getSharedSecret to API reference", async () => { - const api = { - encrypt: async ( - secret: string, - input: Uint8Array, - ): Promise> => - textEncoder.encode(`${secret}:${textDecoder.decode(input)}`), - decrypt: async ( - secret: string, - input: Uint8Array, - ): Promise> => - textEncoder.encode(`${secret}|${textDecoder.decode(input)}`), - encryptText: async (secret: string, plaintext: string): Promise => - `${secret}:${plaintext}`, - decryptText: async ( - secret: string, - ciphertext: string, - ): Promise => `${secret}|${ciphertext}`, - }; - - const actions = createCryptoActions(() => api); - - expect( - textDecoder.decode(await actions.encrypt("s", textEncoder.encode("p"))), - ).toBe("s:p"); - expect( - textDecoder.decode(await actions.decrypt("s", textEncoder.encode("c"))), - ).toBe("s|c"); - expect(await actions.encryptText("s", "p")).toBe("s:p"); - expect(await actions.decryptText("s", "c")).toBe("s|c"); - }); -}); diff --git a/packages/notifications/src/context.tsx b/packages/notifications/src/context.tsx index b5ddf0d..1835dc1 100644 --- a/packages/notifications/src/context.tsx +++ b/packages/notifications/src/context.tsx @@ -141,20 +141,30 @@ export default function Provider(props: { children: React.ReactNode }) { const hasPermissions = await requestNotificationPermission(); if (hasPermissions) { - const notification = new Notification(user.Display, { + const options: NotificationOptions = { body: content, - icon: user.Avatar || user.Display.slice(0, 2).toUpperCase(), - badge: user.Avatar || user.Display.slice(0, 2).toUpperCase(), + icon: user.Avatar || "/icons/icon-192.png", + badge: "/icons/notification-badge.png", tag: `message-${user.UserId}`, silent: true, - }); - + }; + if ("serviceWorker" in navigator) { + const registration = + await navigator.serviceWorker.getRegistration(); + if (registration) { + await registration.showNotification(user.Display, { + ...options, + data: { url: `/chat?id=${user.UserId}` }, + }); + return; + } + } + const notification = new Notification(user.Display, options); notification.onclick = () => { window.focus(); navigate({ to: `/chat?id=${user.UserId}`, }); - notification.close(); }; } else { diff --git a/packages/onboarding/src/index.tsx b/packages/onboarding/src/index.tsx index 5efa9c9..0184776 100644 --- a/packages/onboarding/src/index.tsx +++ b/packages/onboarding/src/index.tsx @@ -21,17 +21,37 @@ export { type OnboardingStepControls, } from "@methanium/ui"; - - interface GateState { docs: z.infer; acceptedPP: boolean; acceptedTOS: boolean; + changedPP: boolean; + changedTOS: boolean; includeLegal: boolean; includeOnboarding: boolean; includeTauriPermissions: boolean; } +async function fetchLegalDocumentHash(document: string) { + const response = await fetch( + `https://legal.methanium.net/tensamin/${document}/raw`, + ); + if (!response.ok) { + throw new Error(`Legal document request failed: ${response.status}`); + } + if (!response.headers.get("content-type")?.startsWith("text/plain")) { + throw new Error("Legal document request returned an invalid content type"); + } + + const hash = await crypto.subtle.digest( + "SHA-256", + await response.arrayBuffer(), + ); + return Array.from(new Uint8Array(hash), (byte) => + byte.toString(16).padStart(2, "0"), + ).join(""); +} + export default function OnboardingGate({ children }: { children: ReactNode }) { const { load, save } = useStorage(); const [state, setState] = useState(); @@ -51,25 +71,9 @@ export default function OnboardingGate({ children }: { children: ReactNode }) { void (async () => { try { - const response = await fetch("https://legal.tensamin.net/api/current"); - if (!response.ok) { - throw new Error(`Legal documents request failed: ${response.status}`); - } - - const current: unknown = await response.json(); - if (!active) return; - - const parsed = legalDocsSchema.safeParse(current); - if (!parsed.success) { - setError("Failed to load legal documents"); - setErrorDescription( - "The legal documents data received from the server is invalid. Please try again later.", - ); - log(0, "Legal", "red", "Invalid legal documents data", parsed.error); - return; - } - const [ + ppHash, + tosHash, localDocs, acceptedPP, acceptedTOS, @@ -77,6 +81,8 @@ export default function OnboardingGate({ children }: { children: ReactNode }) { onboardingStarted, tauriPermissionsDone, ] = await Promise.all([ + fetchLegalDocumentHash("privacy-policy"), + fetchLegalDocumentHash("terms-of-service"), load("legal_docs"), load("accepted_privacy_policy"), load("accepted_terms_of_service"), @@ -87,10 +93,16 @@ export default function OnboardingGate({ children }: { children: ReactNode }) { if (!active) return; + const docs = legalDocsSchema.parse({ + pp: { hash: ppHash }, + tos: { hash: tosHash }, + }); + const changedPP = acceptedPP && localDocs.pp.hash !== docs.pp.hash; + const changedTOS = acceptedTOS && localDocs.tos.hash !== docs.tos.hash; const currentAcceptedPP = - acceptedPP && localDocs.pp.hash === parsed.data.pp.hash; + acceptedPP && localDocs.pp.hash === docs.pp.hash; const currentAcceptedTOS = - acceptedTOS && localDocs.tos.hash === parsed.data.tos.hash; + acceptedTOS && localDocs.tos.hash === docs.tos.hash; const existingUser = acceptedPP && acceptedTOS; const includeOnboarding = !onboardingDone && (!existingUser || onboardingStarted); @@ -104,9 +116,11 @@ export default function OnboardingGate({ children }: { children: ReactNode }) { } setState({ - docs: parsed.data, + docs, acceptedPP: currentAcceptedPP, acceptedTOS: currentAcceptedTOS, + changedPP, + changedTOS, includeLegal: !currentAcceptedPP || !currentAcceptedTOS, includeOnboarding, includeTauriPermissions: @@ -168,16 +182,28 @@ export default function OnboardingGate({ children }: { children: ReactNode }) { const steps: OnboardingStep[] = []; if (state.includeLegal) { + const changedDocuments = [ + state.changedPP && "Privacy Policy", + state.changedTOS && "Terms of Service", + ].filter(Boolean); + steps.push({ id: "legal", - title: "Privacy Policy & ToS", - description: `${state.docs.pp.version} / ${state.docs.tos.version}`, + title: + changedDocuments.length > 0 + ? "Legal documents changed" + : "Privacy Policy & ToS", + description: + changedDocuments.length > 0 + ? changedDocuments.join(" & ") + : "Review and accept our legal documents", defaultCanContinue: false, content: ( ), diff --git a/packages/onboarding/src/pages/legal.tsx b/packages/onboarding/src/pages/legal.tsx index 86c8133..6619ae8 100644 --- a/packages/onboarding/src/pages/legal.tsx +++ b/packages/onboarding/src/pages/legal.tsx @@ -1,21 +1,17 @@ import { useCallback, useState } from "react"; -import { Checkbox, Label, Link } from "@methanium/ui"; -import { legalDocsSchema } from "@tensamin/shared/features/legal/schema"; -import type { z } from "zod"; - -import { useOnboardingStep } from "@methanium/ui"; - - +import { Checkbox, Label, Link, useOnboardingStep } from "@methanium/ui"; export default function LegalPage({ - docs, initiallyAcceptedPP, initiallyAcceptedTOS, + changedPP, + changedTOS, onAccept, }: { - docs: z.infer; initiallyAcceptedPP: boolean; initiallyAcceptedTOS: boolean; + changedPP: boolean; + changedTOS: boolean; onAccept: () => Promise; }) { const [acceptedPP, setAcceptedPP] = useState(initiallyAcceptedPP); @@ -34,34 +30,61 @@ export default function LegalPage({ return (
    -
    - - -
    - - +
    + {!initiallyAcceptedPP && ( + + )} + {!initiallyAcceptedTOS && ( + + )}
    ); } +function LegalDocumentAcceptance({ + id, + name, + link, + changed, + checked, + onChange, +}: { + id: string; + name: string; + link: string; + changed: boolean; + checked: boolean; + onChange: (checked: boolean) => void; +}) { + return ( +
    + + +
    + ); +} + function BigCheckbox({ id, label, diff --git a/packages/shared/src/data.ts b/packages/shared/src/data.ts index 28c5966..eed6e7e 100644 --- a/packages/shared/src/data.ts +++ b/packages/shared/src/data.ts @@ -580,20 +580,11 @@ export const storageDefaults: Storage = { analytics_done: false, ...settingsStorageDefaults, legal_docs: { - eula: { - version: "0.0", - hash: "000000000000", - unix: 0, - }, tos: { - version: "0.0", - hash: "000000000000", - unix: 0, + hash: "0000000000000000000000000000000000000000000000000000000000000000", }, pp: { - version: "0.0", - hash: "000000000000", - unix: 0, + hash: "0000000000000000000000000000000000000000000000000000000000000000", }, }, cached_contacts: [], diff --git a/packages/shared/src/features/legal/schema.ts b/packages/shared/src/features/legal/schema.ts index cbdbf4e..26d35b1 100644 --- a/packages/shared/src/features/legal/schema.ts +++ b/packages/shared/src/features/legal/schema.ts @@ -1,13 +1,10 @@ import { z } from "zod"; const legalDocSchema = z.object({ - version: z.string().regex(/^\d+\.\d+$/), - hash: z.string().regex(/^[a-f0-9]{12}$/), - unix: z.number().int().positive(), + hash: z.string().regex(/^[a-f0-9]{64}$/), }); export const legalDocsSchema = z.object({ - eula: legalDocSchema, tos: legalDocSchema, pp: legalDocSchema, }); diff --git a/packages/storage/package.json b/packages/storage/package.json index 9e19759..dce1554 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -6,7 +6,9 @@ "exports": { "./session": "./src/session.tsx", "./context": "./src/context.tsx", - "./secure": "./src/secure.ts" + "./secure": "./src/secure.ts", + "./browserSecure": "./src/browserSecure.ts", + "./credentials": "./src/credentials.ts" }, "scripts": { "format": "pnpm exec prettier --write .", diff --git a/packages/storage/src/browserSecure.ts b/packages/storage/src/browserSecure.ts new file mode 100644 index 0000000..494b5f0 --- /dev/null +++ b/packages/storage/src/browserSecure.ts @@ -0,0 +1,40 @@ +import { getDatabaseEntry } from "@tensamin/shared/indexedDb"; + +type SecureEnvelope = { + __tensaminSecure: 1; + version: 1; + iv: string; + data: string; +}; + +function base64ToBytes(value: string) { + const binary = atob(value); + return Uint8Array.from(binary, (character) => character.charCodeAt(0)); +} + +function isSecureEnvelope(value: unknown): value is SecureEnvelope { + if (!value || typeof value !== "object") return false; + const envelope = value as Partial; + return ( + envelope.__tensaminSecure === 1 && + envelope.version === 1 && + typeof envelope.iv === "string" && + typeof envelope.data === "string" + ); +} + +export async function loadSecureBrowserValue(key: string) { + const stored = await getDatabaseEntry("storage", key); + if (stored === undefined || !isSecureEnvelope(stored)) { + return stored as T | undefined; + } + + const masterKey = await getDatabaseEntry("keys", "master-v1"); + if (!masterKey) throw new Error("Secure storage key is unavailable."); + const plaintext = await crypto.subtle.decrypt( + { name: "AES-GCM", iv: base64ToBytes(stored.iv) }, + masterKey, + base64ToBytes(stored.data), + ); + return JSON.parse(new TextDecoder().decode(plaintext)) as T; +} diff --git a/packages/storage/src/context.tsx b/packages/storage/src/context.tsx index 27d8759..407adfe 100644 --- a/packages/storage/src/context.tsx +++ b/packages/storage/src/context.tsx @@ -30,7 +30,7 @@ import { export type SaveOptions = { secure?: boolean }; -interface StorageContextValue { +export interface StorageContextValue { load(key: K): Promise; save( key: K, diff --git a/packages/storage/src/credentials.ts b/packages/storage/src/credentials.ts new file mode 100644 index 0000000..7562992 --- /dev/null +++ b/packages/storage/src/credentials.ts @@ -0,0 +1,68 @@ +import { invoke, isTauri } from "@tauri-apps/api/core"; + +import type { StorageContextValue } from "./context"; + +export function parseTuFileContent(rawFileContent: string): { + userId: number; + privateKey: string; + domain: string | null; +} { + const content = rawFileContent.trim(); + const separator = content.indexOf("::"); + if (separator <= 0 || separator !== content.lastIndexOf("::")) { + throw new Error("Invalid file"); + } + + const identity = content.slice(0, separator); + const privateKey = content.slice(separator + 2).trim(); + const [userIdValue, domain, ...extraDomainParts] = identity.split("@"); + const userId = Number(userIdValue); + if ( + !Number.isSafeInteger(userId) || + userId <= 0 || + !privateKey || + extraDomainParts.length > 0 || + (identity.includes("@") && !domain) + ) { + throw new Error("Invalid file"); + } + + return { userId, privateKey, domain: domain ?? null }; +} + +export async function persistMtpCredentials({ + storage, + userId, + keyring, + domain, +}: { + storage: Pick; + userId: number; + keyring: string; + domain?: string | null; +}) { + const omegaUrl = domain + ? `https://${domain}/` + : await storage.load("omega_url"); + if (domain) await storage.save("omega_url", omegaUrl); + + if (isTauri()) { + const [forcedOmikronUrl, forcedOmikronPublicKey] = await Promise.all([ + storage.load("forced_omikron_url"), + storage.load("forced_omikron_public_key"), + ]); + await invoke("mtp_store_credentials", { + config: { + userId, + keyring, + omegaUrl, + forcedOmikronUrl, + forcedOmikronPublicKey, + }, + }); + } + + await storage.save("mtp_keyring", keyring, { secure: true }); + await storage.save("session_id", Date.now()); + await storage.save("user_id", userId); +} diff --git a/packages/storage/src/secure.ts b/packages/storage/src/secure.ts index 283d5c0..367c494 100644 --- a/packages/storage/src/secure.ts +++ b/packages/storage/src/secure.ts @@ -4,10 +4,7 @@ import { getDatabaseEntry, setDatabaseEntry } from "@tensamin/shared/indexedDb"; export type SecureStorageStatus = { backend: - | "electron-keyring" - | "application-storage" - | "webcrypto" - | "indexeddb"; + "electron-keyring" | "application-storage" | "webcrypto" | "indexeddb"; secure: boolean; reason?: string; }; @@ -71,7 +68,12 @@ async function getKey() { if (!globalThis.crypto?.subtle || typeof indexedDB === "undefined") { return null; } - if (window.tensaminDesktop?.secureStorage) return loadElectronKey(); + if ( + typeof window !== "undefined" && + window.tensaminDesktop?.secureStorage + ) { + return loadElectronKey(); + } return loadBrowserKey(); })().catch(() => null); return keyPromise; @@ -120,7 +122,10 @@ export async function decodeSecureValue(value: unknown): Promise { } export async function getSecureStorageStatus(): Promise { - const desktop = window.tensaminDesktop?.secureStorage; + const desktop = + typeof window === "undefined" + ? undefined + : window.tensaminDesktop?.secureStorage; if (desktop?.getStatus) { const status = await desktop.getStatus(); if (status.available) return { backend: "electron-keyring", secure: true }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b9868e6..faff301 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,7 +14,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) mtp: specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz @@ -42,7 +42,7 @@ importers: version: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) eslint-plugin-react-hooks: specifier: ^7.1.1 - version: 7.1.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) + version: 7.1.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) fallow: specifier: ^3.14.0 version: 3.14.0 @@ -60,7 +60,7 @@ importers: version: 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) vitest: specifier: ^4.1.10 - version: 4.1.10(@types/node@26.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.10(@types/node@26.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0)) apps/electron: devDependencies: @@ -72,7 +72,7 @@ importers: version: 43.3.0(supports-color@7.2.0) electron-builder: specifier: ^26.15.3 - version: 26.15.3(electron-builder-squirrel-windows@26.15.3) + version: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) esbuild: specifier: ^0.28.1 version: 0.28.1 @@ -80,17 +80,69 @@ importers: specifier: ~6.0.3 version: 6.0.3 + apps/pwa: + dependencies: + '@methanium/ui': + specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + '@tauri-apps/api': + specifier: ^2.11.1 + version: 2.11.1 + '@tensamin/crypto': + specifier: workspace:* + version: link:../../packages/crypto + '@tensamin/shared': + specifier: workspace:* + version: link:../../packages/shared + '@tensamin/storage': + specifier: workspace:* + version: link:../../packages/storage + mtp: + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz + react: + specifier: ^19.2.8 + version: 19.2.8 + sonner: + specifier: ^2.0.7 + version: 2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + vite-plugin-pwa: + specifier: ^1.1.0 + version: 1.3.0(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0))(workbox-build@7.4.1(supports-color@7.2.0))(workbox-window@7.4.1) + workbox-core: + specifier: ^7.3.0 + version: 7.4.1 + workbox-precaching: + specifier: ^7.3.0 + version: 7.4.1 + workbox-routing: + specifier: ^7.3.0 + version: 7.4.1 + workbox-strategies: + specifier: ^7.3.0 + version: 7.4.1 + devDependencies: + '@types/node': + specifier: ^26.1.2 + version: 26.2.0 + '@types/react': + specifier: ^19.2.18 + version: 19.2.18 + typescript: + specifier: ~6.0.3 + version: 6.0.3 + vite: + specifier: ^8.2.1 + version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) + apps/tauri: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2.11.1 version: 2.11.1 - '@tauri-apps/plugin-barcode-scanner': - specifier: ~2.4.5 - version: 2.4.5 '@tauri-apps/plugin-deep-link': specifier: ~2.4.9 version: 2.4.9 @@ -118,10 +170,10 @@ importers: version: 5.3.0 '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tailwindcss/vite': specifier: ^4.3.3 - version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0)) '@tanstack/react-router': specifier: ^1.170.21 version: 1.170.23(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -155,6 +207,9 @@ importers: '@tensamin/onboarding': specifier: workspace:* version: link:../../packages/onboarding + '@tensamin/pwa': + specifier: workspace:* + version: link:../pwa '@tensamin/settings': specifier: workspace:* version: link:../../packages/settings @@ -212,7 +267,7 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.8.1(jiti@2.7.0)) + version: 10.0.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) '@types/qrcode': specifier: ^1.5.6 version: 1.5.6 @@ -224,13 +279,13 @@ importers: version: 19.2.4(@types/react@19.2.18) '@vitejs/plugin-react': specifier: ^6.0.5 - version: 6.0.5(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) + version: 6.0.5(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0)) esbuild: specifier: ^0.28.1 version: 0.28.1 eslint: specifier: ^10.8.0 - version: 10.8.1(jiti@2.7.0) + version: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) globals: specifier: ^17.9.0 version: 17.9.0 @@ -239,10 +294,10 @@ importers: version: 6.0.3 typescript-eslint: specifier: ^8.66.0 - version: 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + version: 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) vite: specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) packages/cache: dependencies: @@ -269,7 +324,7 @@ importers: version: 2.9.23(livekit-client@2.21.0(@types/dom-mediacapture-record@1.0.22))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tslib@2.8.1) '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.170.21 version: 1.170.23(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -317,7 +372,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/pacer': specifier: ^0.21.1 version: 0.21.1 @@ -393,13 +448,13 @@ importers: devDependencies: vite: specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) packages/mtp: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2.11.1 version: 2.11.1 @@ -427,13 +482,13 @@ importers: devDependencies: eslint: specifier: ^10.8.0 - version: 10.8.1(jiti@2.7.0) + version: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) packages/notifications: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.170.21 version: 1.170.23(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -475,7 +530,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2.11.1 version: 2.11.1 @@ -505,7 +560,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.170.21 version: 1.170.23(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -542,13 +597,13 @@ importers: devDependencies: vite: specifier: ^8.2.1 - version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) packages/shared: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) lucide-react: specifier: ^1.29.0 version: 1.30.0(react@19.2.8) @@ -566,7 +621,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tauri-apps/api': specifier: ^2.11.1 version: 2.11.1 @@ -590,7 +645,7 @@ importers: dependencies: '@methanium/ui': specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3) + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) '@tanstack/react-router': specifier: ^1.170.21 version: 1.170.23(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -645,6 +700,12 @@ importers: packages: + '@apideck/better-ajv-errors@0.3.7': + resolution: {integrity: sha512-TajUJwGWbDwkCx/CZi7tRE8PVB7simCvKJfHUsSdvps+aTM/PDPP4gkLmKnc+x3CE//y9i/nj74GqdL/hwk7Iw==} + engines: {node: '>=10'} + peerDependencies: + ajv: '>=8' + '@babel/code-frame@7.29.7': resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} @@ -675,6 +736,17 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-create-regexp-features-plugin@7.29.7': + resolution: {integrity: sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-define-polyfill-provider@0.6.8': + resolution: {integrity: sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + '@babel/helper-globals@7.29.7': resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} @@ -701,6 +773,12 @@ packages: resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} engines: {node: '>=6.9.0'} + '@babel/helper-remap-async-to-generator@7.29.7': + resolution: {integrity: sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@babel/helper-replace-supers@7.29.7': resolution: {integrity: sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==} engines: {node: '>=6.9.0'} @@ -723,6 +801,10 @@ packages: resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} engines: {node: '>=6.9.0'} + '@babel/helper-wrap-function@7.29.7': + resolution: {integrity: sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==} + engines: {node: '>=6.9.0'} + '@babel/helpers@7.29.7': resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} engines: {node: '>=6.9.0'} @@ -732,6 +814,60 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7': + resolution: {integrity: sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7': + resolution: {integrity: sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7': + resolution: {integrity: sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7': + resolution: {integrity: sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7': + resolution: {integrity: sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7': + resolution: {integrity: sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-assertions@7.29.7': + resolution: {integrity: sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.29.7': + resolution: {integrity: sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-jsx@7.29.7': resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} engines: {node: '>=6.9.0'} @@ -744,18 +880,335 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-arrow-functions@7.29.7': + resolution: {integrity: sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-generator-functions@7.29.7': + resolution: {integrity: sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-to-generator@7.29.7': + resolution: {integrity: sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoped-functions@7.29.7': + resolution: {integrity: sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoping@7.29.7': + resolution: {integrity: sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-properties@7.29.7': + resolution: {integrity: sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-static-block@7.29.7': + resolution: {integrity: sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + + '@babel/plugin-transform-classes@7.29.7': + resolution: {integrity: sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-computed-properties@7.29.7': + resolution: {integrity: sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-destructuring@7.29.7': + resolution: {integrity: sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-dotall-regex@7.29.7': + resolution: {integrity: sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-keys@7.29.7': + resolution: {integrity: sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7': + resolution: {integrity: sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-dynamic-import@7.29.7': + resolution: {integrity: sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-explicit-resource-management@7.29.7': + resolution: {integrity: sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-exponentiation-operator@7.29.7': + resolution: {integrity: sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-export-namespace-from@7.29.7': + resolution: {integrity: sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-for-of@7.29.7': + resolution: {integrity: sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-function-name@7.29.7': + resolution: {integrity: sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-json-strings@7.29.7': + resolution: {integrity: sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-literals@7.29.7': + resolution: {integrity: sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-logical-assignment-operators@7.29.7': + resolution: {integrity: sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-member-expression-literals@7.29.7': + resolution: {integrity: sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-amd@7.29.7': + resolution: {integrity: sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-commonjs@7.29.7': resolution: {integrity: sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-modules-systemjs@7.29.8': + resolution: {integrity: sha512-6iSnEK0zlkLKU4heofK/AdmRD4e2SHVpJMtrwnTCzhnaM98ria4rTrOXBBi45BTTYnJtO8txnPsX4fChYXkmeA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-umd@7.29.7': + resolution: {integrity: sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7': + resolution: {integrity: sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-new-target@7.29.7': + resolution: {integrity: sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7': + resolution: {integrity: sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-numeric-separator@7.29.7': + resolution: {integrity: sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-rest-spread@7.29.7': + resolution: {integrity: sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-super@7.29.7': + resolution: {integrity: sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-catch-binding@7.29.7': + resolution: {integrity: sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-chaining@7.29.7': + resolution: {integrity: sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-parameters@7.29.7': + resolution: {integrity: sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-methods@7.29.7': + resolution: {integrity: sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-property-in-object@7.29.7': + resolution: {integrity: sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-property-literals@7.29.7': + resolution: {integrity: sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regenerator@7.29.8': + resolution: {integrity: sha512-0UpIXPtdDtMXfnV2OJAVMLpj3H/92vmkA6lpSRakmycJvj3VUy6Xs1dM8tXRugupykr5WB+LpiVl0J8LMVg2mg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regexp-modifiers@7.29.7': + resolution: {integrity: sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-reserved-words@7.29.7': + resolution: {integrity: sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-shorthand-properties@7.29.7': + resolution: {integrity: sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-spread@7.29.8': + resolution: {integrity: sha512-4S9ksMGVWUshvgK0mKfvZky7leuG5/uoFVwMpAomJ8bMoDJiNHRVmc1EglwW/CmGVSqqWpEbXm9FmbRit22qoA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-sticky-regex@7.29.7': + resolution: {integrity: sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-template-literals@7.29.7': + resolution: {integrity: sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typeof-symbol@7.29.7': + resolution: {integrity: sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typescript@7.29.7': resolution: {integrity: sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-unicode-escapes@7.29.7': + resolution: {integrity: sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-property-regex@7.29.7': + resolution: {integrity: sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-regex@7.29.7': + resolution: {integrity: sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-sets-regex@7.29.7': + resolution: {integrity: sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/preset-env@7.29.7': + resolution: {integrity: sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-modules@0.1.6-no-external-plugins': + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + '@babel/preset-typescript@7.29.7': resolution: {integrity: sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==} engines: {node: '>=6.9.0'} @@ -1171,6 +1624,10 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@isaacs/cliui@9.0.0': + resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} + engines: {node: '>=18'} + '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -1185,6 +1642,9 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -1266,6 +1726,13 @@ packages: '@cfworker/json-schema': optional: true + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + libc: [glibc] + '@noble/hashes@1.4.0': resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} engines: {node: '>= 16'} @@ -1569,6 +2036,193 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@rollup/plugin-babel@6.1.0': + resolution: {integrity: sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@types/babel__core': ^7.1.9 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + '@types/babel__core': + optional: true + rollup: + optional: true + + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-replace@6.0.3': + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-terser@1.0.0': + resolution: {integrity: sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@5.4.0': + resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.62.4': + resolution: {integrity: sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.62.4': + resolution: {integrity: sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.62.4': + resolution: {integrity: sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.62.4': + resolution: {integrity: sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.62.4': + resolution: {integrity: sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.62.4': + resolution: {integrity: sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.62.4': + resolution: {integrity: sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.62.4': + resolution: {integrity: sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.62.4': + resolution: {integrity: sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.62.4': + resolution: {integrity: sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.62.4': + resolution: {integrity: sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.62.4': + resolution: {integrity: sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.62.4': + resolution: {integrity: sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.62.4': + resolution: {integrity: sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.62.4': + resolution: {integrity: sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.62.4': + resolution: {integrity: sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.62.4': + resolution: {integrity: sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.62.4': + resolution: {integrity: sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.62.4': + resolution: {integrity: sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.62.4': + resolution: {integrity: sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.62.4': + resolution: {integrity: sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.62.4': + resolution: {integrity: sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.62.4': + resolution: {integrity: sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.62.4': + resolution: {integrity: sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.62.4': + resolution: {integrity: sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==} + cpu: [x64] + os: [win32] + '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} @@ -1864,15 +2518,16 @@ packages: engines: {node: '>= 10'} hasBin: true - '@tauri-apps/plugin-barcode-scanner@2.4.5': - resolution: {integrity: sha512-sIPRYEfxww8/y8skZ2LcAp/h5bwvlHkQiq+3w6QEl+2BHs13xnpn7hP+pv4fkBs8DyDfpUbOBIYS5YBwP7x1QQ==} - '@tauri-apps/plugin-deep-link@2.4.9': resolution: {integrity: sha512-u0SKOUHnJ1wqeqXsDFq2+kASCBj9xxbG0g9XZWPy9SOmU4wXtp6b/wiYpm6oH6/5fBTQsLqnLhIvqLBRpgHJlA==} '@tauri-apps/plugin-notification@2.3.3': resolution: {integrity: sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg==} + '@trickfilm400/rollup-plugin-off-main-thread@3.0.0-pre1': + resolution: {integrity: sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==} + engines: {node: '>=12'} + '@ts-morph/common@0.27.0': resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} @@ -1968,9 +2623,15 @@ packages: '@types/react@19.2.18': resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} + '@types/resolve@1.20.2': + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -2210,6 +2871,7 @@ packages: '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version abbrev@4.0.0: resolution: {integrity: sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==} @@ -2285,6 +2947,14 @@ packages: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + asn1js@3.0.10: resolution: {integrity: sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==} engines: {node: '>=12.0.0'} @@ -2301,6 +2971,10 @@ packages: resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==} engines: {node: '>=0.12.0'} + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} @@ -2315,9 +2989,28 @@ packages: resolution: {integrity: sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==} engines: {node: '>=10.12.0'} + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + aws4@1.13.2: resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + babel-plugin-polyfill-corejs2@0.4.17: + resolution: {integrity: sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.14.2: + resolution: {integrity: sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.8: + resolution: {integrity: sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -2401,6 +3094,10 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + engines: {node: '>= 0.4'} + call-bound@1.0.4: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} @@ -2507,6 +3204,9 @@ packages: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@5.1.0: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} engines: {node: '>= 6'} @@ -2519,6 +3219,10 @@ packages: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} + common-tags@1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + compare-version@0.1.2: resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} engines: {node: '>=0.10.0'} @@ -2556,6 +3260,10 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + core-js-compat@3.50.0: + resolution: {integrity: sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==} + engines: {node: '>=6.4.0'} + core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -2582,6 +3290,10 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + crypto-random-string@2.0.0: + resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} + engines: {node: '>=8'} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -2634,6 +3346,18 @@ packages: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + debounce-fn@4.0.0: resolution: {integrity: sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==} engines: {node: '>=10'} @@ -2856,6 +3580,14 @@ packages: error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + es-abstract-get@1.0.0: + resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} + engines: {node: '>= 0.4'} + + es-abstract@1.24.2: + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} + engines: {node: '>= 0.4'} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -2875,6 +3607,10 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} + es-to-primitive@1.3.4: + resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} + engines: {node: '>= 0.4'} + es-toolkit@1.50.0: resolution: {integrity: sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==} @@ -2953,6 +3689,9 @@ packages: estree-util-is-identifier-name@3.0.0: resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -2960,6 +3699,10 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + eta@4.6.0: + resolution: {integrity: sha512-lW6is4T1NFOYnmqGZIfvixqj7A7sSvScF+DN8EK6K58xI5MZ5UvYe0GjopxOXQtZvUn4eDdVuZ8XSoYWTMEKwA==} + engines: {node: '>=20'} + etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} @@ -3079,6 +3822,14 @@ packages: flatted@3.4.4: resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + form-data@4.0.6: resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} engines: {node: '>= 6'} @@ -3137,9 +3888,20 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function.prototype.name@1.2.0: + resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + fuzzysort@3.1.0: resolution: {integrity: sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==} + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -3164,6 +3926,9 @@ packages: resolution: {integrity: sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==} engines: {node: '>=14.16'} + get-own-enumerable-property-symbols@3.0.2: + resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -3180,6 +3945,10 @@ packages: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + github-slugger@2.0.0: resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} @@ -3191,6 +3960,12 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob@11.1.0: + resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} + engines: {node: 20 || >=22} + 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 + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 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 @@ -3218,6 +3993,10 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -3225,6 +4004,10 @@ packages: has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -3327,6 +4110,9 @@ packages: resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} + idb@7.1.1: + resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -3362,6 +4148,10 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + internmap@2.0.3: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} @@ -3380,9 +4170,41 @@ packages: is-alphanumerical@2.0.1: resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} @@ -3396,14 +4218,26 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true + is-document.all@1.0.0: + resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -3424,10 +4258,29 @@ packages: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-obj@1.0.1: + resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==} + engines: {node: '>=0.10.0'} + is-obj@2.0.0: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} @@ -3443,10 +4296,26 @@ packages: is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-regexp@1.0.0: + resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==} + engines: {node: '>=0.10.0'} + is-regexp@3.1.0: resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} engines: {node: '>=12'} + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -3455,6 +4324,18 @@ packages: resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} engines: {node: '>=18'} + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} @@ -3463,6 +4344,18 @@ packages: resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} engines: {node: '>=18'} + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -3474,6 +4367,9 @@ packages: isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isbinaryfile@4.0.10: resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} engines: {node: '>= 8.0.0'} @@ -3497,6 +4393,10 @@ packages: resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} engines: {node: '>=20'} + jackspeak@4.2.3: + resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} + engines: {node: 20 || >=22} + jake@10.9.4: resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} engines: {node: '>=10'} @@ -3556,6 +4456,10 @@ packages: jsonfile@6.2.1: resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + jsonpointer@5.0.1: + resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} + engines: {node: '>=0.10.0'} + katex@0.16.47: resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==} hasBin: true @@ -3578,6 +4482,10 @@ packages: lazy-val@1.0.5: resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -3771,6 +4679,10 @@ packages: resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} engines: {node: '>=8'} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -4124,6 +5036,10 @@ packages: resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==} engines: {node: '>= 10'} + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + obug@2.1.4: resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} engines: {node: '>=12.20.0'} @@ -4165,6 +5081,10 @@ packages: resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} engines: {node: '>=18'} + own-keys@1.0.2: + resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==} + engines: {node: '>= 0.4'} + p-cancelable@2.1.1: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} @@ -4189,6 +5109,9 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -4234,6 +5157,13 @@ packages: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + path-to-regexp@8.4.2: resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} @@ -4271,6 +5201,10 @@ packages: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} engines: {node: '>=10.4.0'} + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + postcss-selector-parser@7.1.5: resolution: {integrity: sha512-KvvtD7SrlBP7dlgkBghEE3r84CABm5SmV2aNcG4oCA+qDnJ/tvKonFVvwWAyyWUEwxuNawdfEAZKP9zM3oZ2Uw==} engines: {node: '>=4'} @@ -4297,6 +5231,14 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-bytes@5.6.0: + resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} + engines: {node: '>=6'} + + pretty-bytes@6.1.1: + resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} + engines: {node: ^14.13.1 || >=16.0.0} + pretty-ms@9.3.0: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} @@ -4456,6 +5398,17 @@ packages: redux@5.0.1: resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regenerate-unicode-properties@10.2.2: + resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} + engines: {node: '>=4'} + + regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + regex-recursion@6.0.2: resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} @@ -4465,6 +5418,21 @@ packages: regex@6.1.0: resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + regexpu-core@6.4.0: + resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} + engines: {node: '>=4'} + + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + + regjsparser@0.13.2: + resolution: {integrity: sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==} + hasBin: true + rehype-autolink-headings@7.1.0: resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==} @@ -4514,6 +5482,11 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + responselike@2.0.1: resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} @@ -4543,6 +5516,11 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rollup@4.62.4: + resolution: {integrity: sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} @@ -4557,9 +5535,21 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} + engines: {node: '>=0.4'} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -4609,6 +5599,10 @@ packages: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} + serialize-javascript@7.1.0: + resolution: {integrity: sha512-RNEqWOyhhUQYN9V1GfHwu9AR/g+NTciH6Z5u3/no6X3/w+04J2lVDL+svFQVXgXrEGBMG2puMVN3gq2SNGuTGw==} + engines: {node: '>=20.0.0'} + seroval-plugins@1.6.2: resolution: {integrity: sha512-TfxuUjlbBESzUOWdTkTKqvSmav0ABym+itetDXLK6mDz8SmrpdI30aF8RTXE8Bvq+tH/1yIDkvy3W0lfQb1ipQ==} engines: {node: '>=10'} @@ -4623,6 +5617,18 @@ packages: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -4676,6 +5682,10 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + smob@1.6.2: + resolution: {integrity: sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==} + engines: {node: '>=20.0.0'} + sonner@2.0.7: resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} peerDependencies: @@ -4703,6 +5713,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.8.0: + resolution: {integrity: sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==} + engines: {node: '>= 12'} + space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -4727,6 +5741,10 @@ packages: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} engines: {node: '>=18'} + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -4735,12 +5753,32 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.trim@1.2.11: + resolution: {integrity: sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.10: + resolution: {integrity: sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} stringify-entities@4.0.4: resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + stringify-object@3.3.0: + resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==} + engines: {node: '>=4'} + stringify-object@5.0.0: resolution: {integrity: sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==} engines: {node: '>=14.16'} @@ -4757,6 +5795,10 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-comments@2.0.1: + resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} + engines: {node: '>=10'} + strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} @@ -4782,6 +5824,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + systeminformation@5.33.1: resolution: {integrity: sha512-DEN6ICHk3Tk0Uf/hrAHh7xlt7iL5CJFBtPZinA0H62DrGG/KPKqq/Nzj6lCXPS4Ay/sf/14zNnk9LpqKzBIc+w==} engines: {node: '>=10.0.0'} @@ -4807,6 +5853,10 @@ packages: resolution: {integrity: sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==} engines: {node: '>=18'} + temp-dir@2.0.0: + resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} + engines: {node: '>=8'} + temp-file@3.4.0: resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} @@ -4814,6 +5864,15 @@ packages: resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} engines: {node: '>=6.0.0'} + tempy@0.6.0: + resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==} + engines: {node: '>=10'} + + terser@5.50.0: + resolution: {integrity: sha512-CN9BVxWhgS/hRxtUMjtC2uRWSTcSfQFHMDWma6sKKfIivCD91sM+FOPfvwoaRMqCSrUpe1nv3jDamd9eEQ4y+w==} + engines: {node: '>=10'} + hasBin: true + tiny-async-pool@1.3.0: resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==} @@ -4886,10 +5945,30 @@ packages: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} + type-fest@0.16.0: + resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} + engines: {node: '>=10'} + type-is@2.1.0: resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} engines: {node: '>= 18'} + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.8: + resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} + engines: {node: '>= 0.4'} + typed-emitter@2.1.0: resolution: {integrity: sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==} @@ -4910,6 +5989,10 @@ packages: engines: {node: '>=16.20.0'} hasBin: true + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} @@ -4924,6 +6007,22 @@ packages: resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==} engines: {node: '>=20.18.1'} + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + engines: {node: '>=4'} + + unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + + unicode-match-property-value-ecmascript@2.2.1: + resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} + engines: {node: '>=4'} + + unicode-property-aliases-ecmascript@2.2.0: + resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} + engines: {node: '>=4'} + unicorn-magic@0.3.0: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} @@ -4931,6 +6030,10 @@ packages: unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + unique-string@2.0.0: + resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} + engines: {node: '>=8'} + unist-util-find-after@5.0.0: resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} @@ -4967,6 +6070,10 @@ packages: unzipper@0.12.5: resolution: {integrity: sha512-tXYOi9R57Uj/2Z25SOs5RRSzq886MBQj2gY8dPL+xl/kv6s6SvByoKfAtvfVeEuhntWDgjd2o9p2lb4TVPAz0A==} + upath@1.2.0: + resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} + engines: {node: '>=4'} + update-browserslist-db@1.3.0: resolution: {integrity: sha512-x/M6q3w4Ybp91CNaS4S69UnliqR3BzRpOT6LWbksjth0S/+jhfaPJsWjt/TewpT8j9eLIojUf5jr29WextHroA==} hasBin: true @@ -5039,6 +6146,18 @@ packages: victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} + vite-plugin-pwa@1.3.0: + resolution: {integrity: sha512-c5kMgN+ITrOtHXp8PAtk2uOIEea6XjP/unCGxOWWBzQ6qa65qj/awHg0wf+QF9E/2u9vh86LqxPwzEPNbM2r5A==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@vite-pwa/assets-generator': ^1.0.0 + vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + workbox-build: ^7.4.1 + workbox-window: ^7.4.1 + peerDependenciesMeta: + '@vite-pwa/assets-generator': + optional: true + vite@8.2.1: resolution: {integrity: sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5136,6 +6255,22 @@ packages: resolution: {integrity: sha512-CHbl2ZQbxx164IgWRgzJno4hWtM4tFbRam1QfI3Yxhs3w/DvqluVxVWeXs3oL5/fbGkSNLKo0Ty5MgUWceNhog==} engines: {node: '>=6.0.0', npm: '>=3.10.0'} + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.22: + resolution: {integrity: sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==} + engines: {node: '>= 0.4'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -5165,6 +6300,55 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + workbox-background-sync@7.4.1: + resolution: {integrity: sha512-HhT7KE8tOWDm02wRNshXUnUPofMlhenF2DBdUnDPOubhizzPeItkYTmAB6td1Z2cjYPa98vzEiPLEuzn5hN66g==} + + workbox-broadcast-update@7.4.1: + resolution: {integrity: sha512-uAlgslKLvbQY+suirIdnBCSYrcgBhjp81Nj4l1lj/Jmj0MJO2CJERnCJjT0GFVwmReV0N+zs78K6gqd5gr9/+A==} + + workbox-build@7.4.1: + resolution: {integrity: sha512-SDhxIvEAde9Gy/5w4Yo1Jh/M49Z0qE3q0oteyE8zGq0DScxFqVBcCtIXFuLtmtxRQZCMbf0prco4VyEu3KBQuw==} + engines: {node: '>=20.0.0'} + + workbox-cacheable-response@7.4.1: + resolution: {integrity: sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==} + + workbox-core@7.4.1: + resolution: {integrity: sha512-DT+vu46eh/2vRsSHTY4Xmc32Z1rr9PRlQUXr1Dx30ZuXRWwOsvZgGgcwxcasubQLQmbTNYZjv44LkBAQ4tT5tQ==} + + workbox-expiration@7.4.1: + resolution: {integrity: sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==} + + workbox-google-analytics@7.4.1: + resolution: {integrity: sha512-Mks1JwLEt++ZAkF6sS1OpSh9RtAMIsiDgRpK+codiHGIPXeaUOgi4cPc3GFadUl8V5QPeypEk8Oxgl3HlwVzHw==} + + workbox-navigation-preload@7.4.1: + resolution: {integrity: sha512-C4KVsjPcYKJOhr631AxR9XoG2rLF3QiTk5aMv36MXOjtWvm8axwNFAtKUPGsWUwLXXAMgYM1En7fsvndaXeXRQ==} + + workbox-precaching@7.4.1: + resolution: {integrity: sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==} + + workbox-range-requests@7.4.1: + resolution: {integrity: sha512-7i2oxAUE82gHdAJBCAQ04JzNOdRPqzuOzGfoUyJpFSmeqBNYGPrAH8GPoPjUQTfp+NycwrD2H68VtuF8qxv0vQ==} + + workbox-recipes@7.4.1: + resolution: {integrity: sha512-gnbVfmV4/TtmQaM4x9AtuXhcdstJsep3XMVeztOrQVPT+R6+6DeBjGTCQ7fFCXm+4GEHUA5VEBTyi5+4gWGeog==} + + workbox-routing@7.4.1: + resolution: {integrity: sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==} + + workbox-strategies@7.4.1: + resolution: {integrity: sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==} + + workbox-streams@7.4.1: + resolution: {integrity: sha512-HWWtraKUbJknd9kgqGcpQ3G114HOPYvqs8HaJMDs2ebLNAimDkVDaWfAXE6Ybl+m8U6KsCE6pWyLYuigWmnAXw==} + + workbox-sw@7.4.1: + resolution: {integrity: sha512-fez5f2DUlDJWTFYkCWQpY10N8gtztd849NswCbVFk0QlcSM4HT5A8x4g4ii650yem4I8tHY0R7JZahwp3ltIPw==} + + workbox-window@7.4.1: + resolution: {integrity: sha512-notZDH2u8VXaqyuD7xaqIfEFi6SRM4SUSd7ewe9PDsVqADuepxX2ZMY3uvuZGxzY5ZOsGC/vD3A/3smFtJt4/A==} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -5259,6 +6443,12 @@ packages: snapshots: + '@apideck/better-ajv-errors@0.3.7(ajv@8.20.0)': + dependencies: + ajv: 8.20.0 + jsonpointer: 5.0.1 + leven: 3.1.0 + '@babel/code-frame@7.29.7': dependencies: '@babel/helper-validator-identifier': 7.29.7 @@ -5267,16 +6457,16 @@ snapshots: '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.7': + '@babel/core@7.29.7(supports-color@7.2.0)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.8 '@babel/helper-compilation-targets': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helpers': 7.29.7 '@babel/parser': 7.29.8 '@babel/template': 7.29.7 - '@babel/traverse': 7.29.8 + '@babel/traverse': 7.29.8(supports-color@7.2.0) '@babel/types': 7.29.8 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 @@ -5307,41 +6497,59 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@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@7.2.0) '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) - '@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.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) + '@babel/traverse': 7.29.8(supports-color@7.2.0) semver: 6.3.1 transitivePeerDependencies: - supports-color + '@babel/helper-create-regexp-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-annotate-as-pure': 7.29.7 + regexpu-core: 6.4.0 + semver: 6.3.1 + + '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + debug: 4.4.3(supports-color@7.2.0) + lodash.debounce: 4.0.8 + resolve: 1.22.12 + transitivePeerDependencies: + - supports-color + '@babel/helper-globals@7.29.7': {} - '@babel/helper-member-expression-to-functions@7.29.7': + '@babel/helper-member-expression-to-functions@7.29.7(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.8 + '@babel/traverse': 7.29.8(supports-color@7.2.0) '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.29.7': + '@babel/helper-module-imports@7.29.7(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.8 + '@babel/traverse': 7.29.8(supports-color@7.2.0) '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-imports': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-module-imports': 7.29.7(supports-color@7.2.0) '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.8 + '@babel/traverse': 7.29.8(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -5351,18 +6559,27 @@ snapshots: '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': + '@babel/helper-remap-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.29.7 - '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/traverse': 7.29.8 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-wrap-function': 7.29.7(supports-color@7.2.0) + '@babel/traverse': 7.29.8(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.8 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@7.2.0) + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7(supports-color@7.2.0)': + dependencies: + '@babel/traverse': 7.29.8(supports-color@7.2.0) '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -5373,6 +6590,14 @@ snapshots: '@babel/helper-validator-option@7.29.7': {} + '@babel/helper-wrap-function@7.29.7(supports-color@7.2.0)': + dependencies: + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@7.2.0) + '@babel/types': 7.29.8 + transitivePeerDependencies: + - supports-color + '@babel/helpers@7.29.7': dependencies: '@babel/template': 7.29.7 @@ -5382,43 +6607,515 @@ snapshots: dependencies: '@babel/types': 7.29.8 - '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + + '@babel/plugin-syntax-import-assertions@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-arrow-functions@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-async-generator-functions@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/traverse': 7.29.8(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-module-imports': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-block-scoped-functions@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-block-scoping@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-class-properties@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-class-static-block@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-globals': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/traverse': 7.29.8(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.29.7(@babel/core@7.29.7)': + '@babel/plugin-transform-computed-properties@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/template': 7.29.7 + + '@babel/plugin-transform-destructuring@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-dotall-regex@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-duplicate-keys@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-dynamic-import@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-explicit-resource-management@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-exponentiation-operator@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-export-namespace-from@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-for-of@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-function-name@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-json-strings@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-literals@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-logical-assignment-operators@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-member-expression-literals@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-modules-amd@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-systemjs@7.29.8(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-umd@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-new-target@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-numeric-separator@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-object-rest-spread@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/traverse': 7.29.8(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-object-super@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-optional-chaining@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-parameters@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-property-in-object@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-property-literals@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-regenerator@7.29.8(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-regexp-modifiers@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-reserved-words@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-shorthand-properties@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-spread@7.29.8(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-sticky-regex@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-template-literals@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-typeof-symbol@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@7.2.0) + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-unicode-escapes@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-property-regex@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-regex@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-sets-regex@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/preset-env@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-option': 7.29.7 - '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-syntax-import-assertions': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-block-scoped-functions': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-class-static-block': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-computed-properties': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-dotall-regex': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-duplicate-keys': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-dynamic-import': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-explicit-resource-management': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-exponentiation-operator': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-export-namespace-from': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-function-name': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-json-strings': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-literals': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-logical-assignment-operators': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-member-expression-literals': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-modules-amd': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-modules-systemjs': 7.29.8(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-modules-umd': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-new-target': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-numeric-separator': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-object-rest-spread': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-object-super': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-property-literals': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-regenerator': 7.29.8(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-regexp-modifiers': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-reserved-words': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-spread': 7.29.8(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-sticky-regex': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-typeof-symbol': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-unicode-escapes': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-unicode-property-regex': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-unicode-sets-regex': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.7(supports-color@7.2.0)) + babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + core-js-compat: 3.50.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.7(supports-color@7.2.0))': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/types': 7.29.8 + esutils: 2.0.3 + + '@babel/preset-typescript@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0)) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -5430,7 +7127,7 @@ snapshots: '@babel/parser': 7.29.8 '@babel/types': 7.29.8 - '@babel/traverse@7.29.8': + '@babel/traverse@7.29.8(supports-color@7.2.0)': dependencies: '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.8 @@ -5587,7 +7284,7 @@ snapshots: fs-extra: 9.1.0 minimist: 1.2.8 - '@electron/get@3.1.0': + '@electron/get@3.1.0(supports-color@7.2.0)': dependencies: debug: 4.4.3(supports-color@7.2.0) env-paths: 2.2.1 @@ -5595,7 +7292,7 @@ snapshots: got: 11.8.6 progress: 2.0.3 semver: 6.3.1 - sumchecker: 3.0.1 + sumchecker: 3.0.1(supports-color@7.2.0) optionalDependencies: global-agent: 3.0.0 transitivePeerDependencies: @@ -5608,13 +7305,13 @@ snapshots: graceful-fs: 4.2.11 progress: 2.0.3 semver: 7.8.5 - sumchecker: 3.0.1 + sumchecker: 3.0.1(supports-color@7.2.0) optionalDependencies: undici: 7.29.0 transitivePeerDependencies: - supports-color - '@electron/notarize@2.5.0': + '@electron/notarize@2.5.0(supports-color@7.2.0)': dependencies: debug: 4.4.3(supports-color@7.2.0) fs-extra: 9.1.0 @@ -5622,7 +7319,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/osx-sign@1.3.3': + '@electron/osx-sign@1.3.3(supports-color@7.2.0)': dependencies: compare-version: 0.1.2 debug: 4.4.3(supports-color@7.2.0) @@ -5633,18 +7330,18 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/rebuild@4.2.0': + '@electron/rebuild@4.2.0(supports-color@7.2.0)': dependencies: '@malept/cross-spawn-promise': 2.0.0 debug: 4.4.3(supports-color@7.2.0) node-abi: 4.33.0 node-api-version: 0.2.1 node-gyp: 12.4.0 - read-binary-file-arch: 1.0.6 + read-binary-file-arch: 1.0.6(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@electron/universal@2.0.3': + '@electron/universal@2.0.3(supports-color@7.2.0)': dependencies: '@electron/asar': 3.4.1 '@malept/cross-spawn-promise': 2.0.0 @@ -5656,7 +7353,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/windows-sign@1.2.2': + '@electron/windows-sign@1.2.2(supports-color@7.2.0)': dependencies: cross-dirname: 0.1.0 debug: 4.4.3(supports-color@7.2.0) @@ -5750,11 +7447,6 @@ snapshots: eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.10.1(eslint@10.8.1(jiti@2.7.0))': - dependencies: - eslint: 10.8.1(jiti@2.7.0) - eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.12.2': {} '@eslint/config-array@0.23.5(supports-color@7.2.0)': @@ -5777,10 +7469,6 @@ snapshots: optionalDependencies: eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) - '@eslint/js@10.0.1(eslint@10.8.1(jiti@2.7.0))': - optionalDependencies: - eslint: 10.8.1(jiti@2.7.0) - '@eslint/object-schema@3.0.5': {} '@eslint/plugin-kit@0.7.2': @@ -5856,6 +7544,8 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@isaacs/cliui@9.0.0': {} + '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.3 @@ -5872,6 +7562,11 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': @@ -5942,7 +7637,7 @@ snapshots: dependencies: cross-spawn: 7.0.6 - '@malept/flatpak-bundler@0.4.0': + '@malept/flatpak-bundler@0.4.0(supports-color@7.2.0)': dependencies: debug: 4.4.3(supports-color@7.2.0) fs-extra: 9.1.0 @@ -5953,7 +7648,7 @@ snapshots: '@marijn/find-cluster-break@1.0.3': {} - '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(typescript@6.0.3)': + '@methanium/ui@https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@base-ui/react': 1.7.0(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@codemirror/autocomplete': 6.20.3 @@ -5969,23 +7664,23 @@ snapshots: cmdk: 1.1.1(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) embla-carousel-react: 8.6.0(react@19.2.8) emojibase-data: 17.0.0(emojibase@17.0.0) - hast-util-to-jsx-runtime: 2.3.6 + hast-util-to-jsx-runtime: 2.3.6(supports-color@7.2.0) input-otp: 1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) katex: 0.18.4 lucide-react: 1.31.0(react@19.2.8) next-themes: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - react-markdown: 10.1.0(@types/react@19.2.18)(react@19.2.8) + react-markdown: 10.1.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) react-resizable-panels: 4.12.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) recharts: 3.10.1(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1) rehype-autolink-headings: 7.1.0 rehype-katex: 7.0.1 rehype-slug: 6.0.0 remark-breaks: 4.0.0 - remark-gfm: 4.0.1 - remark-math: 6.0.0 - shadcn: 4.16.2(typescript@6.0.3) + remark-gfm: 4.0.1(supports-color@7.2.0) + remark-math: 6.0.0(supports-color@7.2.0) + shadcn: 4.16.2(supports-color@7.2.0)(typescript@6.0.3) shiki: 4.4.2 sonner: 2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) tailwind-merge: 3.6.0 @@ -6005,7 +7700,7 @@ snapshots: - supports-color - typescript - '@modelcontextprotocol/sdk@1.30.0(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.30.0(supports-color@7.2.0)(zod@3.25.76)': dependencies: '@hono/node-server': 2.1.0(hono@4.13.1) ajv: 8.20.0 @@ -6015,8 +7710,8 @@ snapshots: cross-spawn: 7.0.6 eventsource: 3.0.7 eventsource-parser: 3.1.0 - express: 5.2.1 - express-rate-limit: 8.6.2(express@5.2.1) + express: 5.2.1(supports-color@7.2.0) + express-rate-limit: 8.6.2(express@5.2.1(supports-color@7.2.0))(supports-color@7.2.0) hono: 4.13.1 jose: 6.2.8 json-schema-typed: 8.0.2 @@ -6027,6 +7722,9 @@ snapshots: transitivePeerDependencies: - supports-color + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + '@noble/hashes@1.4.0': {} '@noble/hashes@2.3.0': {} @@ -6260,6 +7958,124 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} + '@rollup/plugin-babel@6.1.0(@babel/core@7.29.7(supports-color@7.2.0))(rollup@4.62.4)(supports-color@7.2.0)': + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-module-imports': 7.29.7(supports-color@7.2.0) + '@rollup/pluginutils': 5.4.0(rollup@4.62.4) + optionalDependencies: + rollup: 4.62.4 + transitivePeerDependencies: + - supports-color + + '@rollup/plugin-node-resolve@16.0.3(rollup@4.62.4)': + dependencies: + '@rollup/pluginutils': 5.4.0(rollup@4.62.4) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.12 + optionalDependencies: + rollup: 4.62.4 + + '@rollup/plugin-replace@6.0.3(rollup@4.62.4)': + dependencies: + '@rollup/pluginutils': 5.4.0(rollup@4.62.4) + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.62.4 + + '@rollup/plugin-terser@1.0.0(rollup@4.62.4)': + dependencies: + serialize-javascript: 7.1.0 + smob: 1.6.2 + terser: 5.50.0 + optionalDependencies: + rollup: 4.62.4 + + '@rollup/pluginutils@5.4.0(rollup@4.62.4)': + dependencies: + '@types/estree': 1.0.9 + estree-walker: 2.0.2 + picomatch: 4.0.5 + optionalDependencies: + rollup: 4.62.4 + + '@rollup/rollup-android-arm-eabi@4.62.4': + optional: true + + '@rollup/rollup-android-arm64@4.62.4': + optional: true + + '@rollup/rollup-darwin-arm64@4.62.4': + optional: true + + '@rollup/rollup-darwin-x64@4.62.4': + optional: true + + '@rollup/rollup-freebsd-arm64@4.62.4': + optional: true + + '@rollup/rollup-freebsd-x64@4.62.4': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.62.4': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.62.4': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-x64-musl@4.62.4': + optional: true + + '@rollup/rollup-openbsd-x64@4.62.4': + optional: true + + '@rollup/rollup-openharmony-arm64@4.62.4': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.62.4': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.62.4': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.62.4': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.62.4': + optional: true + '@sec-ant/readable-stream@0.4.1': {} '@shikijs/core@4.4.2': @@ -6375,12 +8191,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 - '@tailwindcss/vite@4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': + '@tailwindcss/vite@4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.3 '@tailwindcss/oxide': 4.3.3 tailwindcss: 4.3.3 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) '@tanstack/devtools-event-client@0.4.4': {} @@ -6500,10 +8316,6 @@ snapshots: '@tauri-apps/cli-win32-ia32-msvc': 2.11.4 '@tauri-apps/cli-win32-x64-msvc': 2.11.4 - '@tauri-apps/plugin-barcode-scanner@2.4.5': - dependencies: - '@tauri-apps/api': 2.11.1 - '@tauri-apps/plugin-deep-link@2.4.9': dependencies: '@tauri-apps/api': 2.11.1 @@ -6512,6 +8324,13 @@ snapshots: dependencies: '@tauri-apps/api': 2.11.1 + '@trickfilm400/rollup-plugin-off-main-thread@3.0.0-pre1': + dependencies: + ejs: 3.1.10 + json5: 2.2.3 + magic-string: 0.30.21 + string.prototype.matchall: 4.0.12 + '@ts-morph/common@0.27.0': dependencies: fast-glob: 3.3.3 @@ -6614,10 +8433,14 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/resolve@1.20.2': {} + '@types/responselike@1.0.3': dependencies: '@types/node': 26.2.0 + '@types/trusted-types@2.0.7': {} + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -6632,7 +8455,7 @@ snapshots: '@typescript-eslint/parser': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.66.0 '@typescript-eslint/type-utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.66.0 eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) ignore: 7.0.6 @@ -6642,22 +8465,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.66.0 - '@typescript-eslint/type-utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.66.0 - eslint: 10.8.1(jiti@2.7.0) - ignore: 7.0.6 - natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.66.0 @@ -6670,18 +8477,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.66.0 - '@typescript-eslint/types': 8.66.0 - '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.66.0 - debug: 4.4.3(supports-color@7.2.0) - eslint: 10.8.1(jiti@2.7.0) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/project-service@8.66.0(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.66.0(typescript@6.0.3) @@ -6704,7 +8499,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.66.0 '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) debug: 4.4.3(supports-color@7.2.0) eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) ts-api-utils: 2.5.0(typescript@6.0.3) @@ -6712,18 +8507,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': - dependencies: - '@typescript-eslint/types': 8.66.0 - '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) - debug: 4.4.3(supports-color@7.2.0) - eslint: 10.8.1(jiti@2.7.0) - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/types@8.66.0': {} '@typescript-eslint/typescript-estree@8.66.0(supports-color@7.2.0)(typescript@6.0.3)': @@ -6741,7 +8524,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3)': + '@typescript-eslint/utils@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) '@typescript-eslint/scope-manager': 8.66.0 @@ -6752,17 +8535,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': - dependencies: - '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)) - '@typescript-eslint/scope-manager': 8.66.0 - '@typescript-eslint/types': 8.66.0 - '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/visitor-keys@8.66.0': dependencies: '@typescript-eslint/types': 8.66.0 @@ -6830,10 +8602,10 @@ snapshots: '@ungap/structured-clone@1.3.3': {} - '@vitejs/plugin-react@6.0.5(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': + '@vitejs/plugin-react@6.0.5(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) '@vitest/expect@4.1.10': dependencies: @@ -6844,13 +8616,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.1 - '@vitest/mocker@4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) '@vitest/pretty-format@4.1.10': dependencies: @@ -6925,33 +8697,33 @@ snapshots: dependencies: color-convert: 2.0.1 - app-builder-lib@26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3): + app-builder-lib@26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): dependencies: '@electron/asar': 3.4.1 '@electron/fuses': 1.8.0 - '@electron/get': 3.1.0 - '@electron/notarize': 2.5.0 - '@electron/osx-sign': 1.3.3 - '@electron/rebuild': 4.2.0 - '@electron/universal': 2.0.3 - '@malept/flatpak-bundler': 0.4.0 + '@electron/get': 3.1.0(supports-color@7.2.0) + '@electron/notarize': 2.5.0(supports-color@7.2.0) + '@electron/osx-sign': 1.3.3(supports-color@7.2.0) + '@electron/rebuild': 4.2.0(supports-color@7.2.0) + '@electron/universal': 2.0.3(supports-color@7.2.0) + '@malept/flatpak-bundler': 0.4.0(supports-color@7.2.0) '@noble/hashes': 2.3.0 '@peculiar/webcrypto': 1.7.1 '@types/fs-extra': 9.0.13 ajv: 8.20.0 asn1js: 3.0.10 async-exit-hook: 2.0.1 - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chromium-pickle-js: 0.2.0 ci-info: 4.3.1 debug: 4.4.3(supports-color@7.2.0) - dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) dotenv: 16.6.1 dotenv-expand: 11.0.7 ejs: 3.1.10 - electron-builder-squirrel-windows: 26.15.3(dmg-builder@26.15.3) - electron-publish: 26.15.3 + electron-builder-squirrel-windows: 26.15.3(dmg-builder@26.15.3)(supports-color@7.2.0) + electron-publish: 26.15.3(supports-color@7.2.0) fs-extra: 10.1.0 hosted-git-info: 4.1.0 isbinaryfile: 5.0.7 @@ -6979,6 +8751,21 @@ snapshots: dependencies: tslib: 2.8.1 + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + asn1js@3.0.10: dependencies: pvtsutils: 1.3.6 @@ -6993,6 +8780,8 @@ snapshots: async-exit-hook@2.0.1: {} + async-function@1.0.0: {} + async@3.2.6: {} asynckit@0.4.0: {} @@ -7001,8 +8790,36 @@ snapshots: atomically@1.7.0: {} + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + aws4@1.13.2: {} + babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0): + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0): + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + core-js-compat: 3.50.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0): + dependencies: + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -7015,7 +8832,7 @@ snapshots: bluebird@3.7.2: {} - body-parser@2.3.0: + body-parser@2.3.0(supports-color@7.2.0): dependencies: bytes: 3.1.2 content-type: 2.0.0 @@ -7059,23 +8876,23 @@ snapshots: buffer-from@1.1.2: {} - builder-util-runtime@9.7.0: + builder-util-runtime@9.7.0(supports-color@7.2.0): dependencies: debug: 4.4.3(supports-color@7.2.0) sax: 1.6.1 transitivePeerDependencies: - supports-color - builder-util@26.15.3: + builder-util@26.15.3(supports-color@7.2.0): dependencies: '@types/debug': 4.1.13 - builder-util-runtime: 9.7.0 + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3(supports-color@7.2.0) fs-extra: 10.1.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + http-proxy-agent: 7.0.2(supports-color@7.2.0) + https-proxy-agent: 7.0.6(supports-color@7.2.0) js-yaml: 4.3.1 sanitize-filename: 1.6.4 source-map-support: 0.5.21 @@ -7110,6 +8927,13 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + call-bound@1.0.4: dependencies: call-bind-apply-helpers: 1.0.2 @@ -7198,6 +9022,8 @@ snapshots: commander@14.0.3: {} + commander@2.20.3: {} + commander@5.1.0: {} commander@8.3.0: {} @@ -7205,6 +9031,8 @@ snapshots: commander@9.5.0: optional: true + common-tags@1.8.2: {} + compare-version@0.1.2: {} concat-map@0.0.1: {} @@ -7236,6 +9064,10 @@ snapshots: cookie@0.7.2: {} + core-js-compat@3.50.0: + dependencies: + browserslist: 4.28.7 + core-util-is@1.0.3: {} cors@2.8.6: @@ -7263,6 +9095,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + crypto-random-string@2.0.0: {} + cssesc@3.0.0: {} csstype@3.2.3: {} @@ -7305,6 +9139,24 @@ snapshots: d3-timer@3.0.1: {} + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + debounce-fn@4.0.0: dependencies: mimic-fn: 3.1.0 @@ -7349,7 +9201,6 @@ snapshots: es-define-property: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 - optional: true define-lazy-prop@2.0.0: {} @@ -7360,7 +9211,6 @@ snapshots: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 - optional: true delayed-stream@1.0.0: {} @@ -7386,10 +9236,10 @@ snapshots: minimatch: 3.1.5 p-limit: 3.1.0 - dmg-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): + dmg-builder@26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) fs-extra: 10.1.0 js-yaml: 4.3.1 transitivePeerDependencies: @@ -7424,23 +9274,23 @@ snapshots: dependencies: jake: 10.9.4 - electron-builder-squirrel-windows@26.15.3(dmg-builder@26.15.3): + electron-builder-squirrel-windows@26.15.3(dmg-builder@26.15.3)(supports-color@7.2.0): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 - electron-winstaller: 5.4.0 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) + electron-winstaller: 5.4.0(supports-color@7.2.0) transitivePeerDependencies: - dmg-builder - supports-color - electron-builder@26.15.3(electron-builder-squirrel-windows@26.15.3): + electron-builder@26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0): dependencies: - app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3) - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + app-builder-lib: 26.15.3(dmg-builder@26.15.3)(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 ci-info: 4.4.0 - dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3) + dmg-builder: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0) fs-extra: 10.1.0 lazy-val: 1.0.5 simple-update-notifier: 2.0.0 @@ -7449,12 +9299,12 @@ snapshots: - electron-builder-squirrel-windows - supports-color - electron-publish@26.15.3: + electron-publish@26.15.3(supports-color@7.2.0): dependencies: '@types/fs-extra': 9.0.13 aws4: 1.13.2 - builder-util: 26.15.3 - builder-util-runtime: 9.7.0 + builder-util: 26.15.3(supports-color@7.2.0) + builder-util-runtime: 9.7.0(supports-color@7.2.0) chalk: 4.1.2 form-data: 4.0.6 fs-extra: 10.1.0 @@ -7465,7 +9315,7 @@ snapshots: electron-to-chromium@1.5.402: {} - electron-winstaller@5.4.0: + electron-winstaller@5.4.0(supports-color@7.2.0): dependencies: '@electron/asar': 3.4.1 debug: 4.4.3(supports-color@7.2.0) @@ -7473,7 +9323,7 @@ snapshots: lodash: 4.18.1 temp: 0.9.4 optionalDependencies: - '@electron/windows-sign': 1.2.2 + '@electron/windows-sign': 1.2.2(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -7535,6 +9385,70 @@ snapshots: dependencies: is-arrayish: 0.2.1 + es-abstract-get@1.0.0: + dependencies: + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + is-callable: 1.2.7 + object-inspect: 1.13.4 + + es-abstract@1.24.2: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.4 + function.prototype.name: 1.2.0 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.2 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.4 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.11 + string.prototype.trimend: 1.0.10 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.8 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.22 + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -7552,6 +9466,15 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.4 + es-to-primitive@1.3.4: + dependencies: + es-abstract-get: 1.0.0 + es-define-property: 1.0.1 + es-errors: 1.3.0 + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + es-toolkit@1.50.0: {} es6-error@4.1.1: @@ -7594,9 +9517,9 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-plugin-react-hooks@7.1.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)): + eslint-plugin-react-hooks@7.1.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/parser': 7.29.8 eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) hermes-parser: 0.25.1 @@ -7616,43 +9539,6 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.8.1(jiti@2.7.0): - dependencies: - '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.5(supports-color@7.2.0) - '@eslint/config-helpers': 0.7.0 - '@eslint/core': 1.2.1 - '@eslint/plugin-kit': 0.7.2 - '@humanfs/node': 0.16.8 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.9 - ajv: 6.15.0 - cross-spawn: 7.0.6 - debug: 4.4.3(supports-color@7.2.0) - escape-string-regexp: 4.0.0 - eslint-scope: 9.1.2 - eslint-visitor-keys: 5.0.1 - espree: 11.2.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.6 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.7.0 - transitivePeerDependencies: - - supports-color - eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0): dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) @@ -7710,12 +9596,16 @@ snapshots: estree-util-is-identifier-name@3.0.0: {} + estree-walker@2.0.2: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.9 esutils@2.0.3: {} + eta@4.6.0: {} + etag@1.8.1: {} eventemitter3@5.0.4: {} @@ -7759,18 +9649,18 @@ snapshots: exponential-backoff@3.1.3: {} - express-rate-limit@8.6.2(express@5.2.1): + express-rate-limit@8.6.2(express@5.2.1(supports-color@7.2.0))(supports-color@7.2.0): dependencies: debug: 4.4.3(supports-color@7.2.0) - express: 5.2.1 + express: 5.2.1(supports-color@7.2.0) ip-address: 10.4.0 transitivePeerDependencies: - supports-color - express@5.2.1: + express@5.2.1(supports-color@7.2.0): dependencies: accepts: 2.0.0 - body-parser: 2.3.0 + body-parser: 2.3.0(supports-color@7.2.0) content-disposition: 1.1.0 content-type: 1.0.5 cookie: 0.7.2 @@ -7780,7 +9670,7 @@ snapshots: encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 2.1.1 + finalhandler: 2.1.1(supports-color@7.2.0) fresh: 2.0.0 http-errors: 2.0.1 merge-descriptors: 2.0.0 @@ -7791,9 +9681,9 @@ snapshots: proxy-addr: 2.0.7 qs: 6.15.3 range-parser: 1.3.0 - router: 2.2.0 - send: 1.2.1 - serve-static: 2.2.1 + router: 2.2.0(supports-color@7.2.0) + send: 1.2.1(supports-color@7.2.0) + serve-static: 2.2.1(supports-color@7.2.0) statuses: 2.0.2 type-is: 2.1.0 vary: 1.1.2 @@ -7861,7 +9751,7 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.1: + finalhandler@2.1.1(supports-color@7.2.0): dependencies: debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 @@ -7888,6 +9778,15 @@ snapshots: flatted@3.4.4: {} + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + form-data@4.0.6: dependencies: asynckit: 0.4.0 @@ -7953,8 +9852,24 @@ snapshots: function-bind@1.1.2: {} + function.prototype.name@1.2.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + es-define-property: 1.0.1 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + hasown: 2.0.4 + is-callable: 1.2.7 + is-document.all: 1.0.0 + + functions-have-names@1.2.3: {} + fuzzysort@3.1.0: {} + generator-function@2.0.1: {} + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -7978,6 +9893,8 @@ snapshots: get-own-enumerable-keys@1.0.0: {} + get-own-enumerable-property-symbols@3.0.2: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -7994,6 +9911,12 @@ snapshots: '@sec-ant/readable-stream': 0.4.1 is-stream: 4.0.1 + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + github-slugger@2.0.0: {} glob-parent@5.1.2: @@ -8004,6 +9927,15 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@11.1.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.2.3 + minimatch: 10.2.6 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.2 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -8029,7 +9961,6 @@ snapshots: dependencies: define-properties: 1.2.1 gopd: 1.2.0 - optional: true gopd@1.2.0: {} @@ -8049,12 +9980,17 @@ snapshots: graceful-fs@4.2.11: {} + has-bigints@1.1.0: {} + has-flag@4.0.0: {} has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 - optional: true + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 has-symbols@1.1.0: {} @@ -8125,7 +10061,7 @@ snapshots: stringify-entities: 4.0.4 zwitch: 2.0.4 - hast-util-to-jsx-runtime@2.3.6: + hast-util-to-jsx-runtime@2.3.6(supports-color@7.2.0): dependencies: '@types/estree': 1.0.9 '@types/hast': 3.0.5 @@ -8134,9 +10070,9 @@ snapshots: devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 hast-util-whitespace: 3.0.0 - mdast-util-mdx-expression: 2.0.1 - mdast-util-mdx-jsx: 3.2.0 - mdast-util-mdxjs-esm: 2.0.1 + mdast-util-mdx-expression: 2.0.1(supports-color@7.2.0) + mdast-util-mdx-jsx: 3.2.0(supports-color@7.2.0) + mdast-util-mdxjs-esm: 2.0.1(supports-color@7.2.0) property-information: 7.2.0 space-separated-tokens: 2.0.2 style-to-js: 1.1.21 @@ -8194,7 +10130,7 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 - http-proxy-agent@7.0.2: + http-proxy-agent@7.0.2(supports-color@7.2.0): dependencies: agent-base: 7.1.4 debug: 4.4.3(supports-color@7.2.0) @@ -8206,7 +10142,7 @@ snapshots: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - https-proxy-agent@7.0.6: + https-proxy-agent@7.0.6(supports-color@7.2.0): dependencies: agent-base: 7.1.4 debug: 4.4.3(supports-color@7.2.0) @@ -8221,6 +10157,8 @@ snapshots: dependencies: safer-buffer: 2.1.2 + idb@7.1.1: {} + ignore@5.3.2: {} ignore@7.0.6: {} @@ -8248,6 +10186,12 @@ snapshots: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.4 + side-channel: 1.1.1 + internmap@2.0.3: {} ip-address@10.4.0: {} @@ -8261,18 +10205,74 @@ snapshots: is-alphabetical: 2.0.1 is-decimal: 2.0.1 + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-arrayish@0.2.1: {} + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-core-module@2.16.2: + dependencies: + hasown: 2.0.4 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + is-decimal@2.0.1: {} is-docker@2.2.1: {} is-docker@3.0.0: {} + is-document.all@1.0.0: + dependencies: + call-bound: 1.0.4 + is-extglob@2.1.1: {} + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + is-fullwidth-code-point@3.0.0: {} + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -8287,8 +10287,21 @@ snapshots: is-interactive@2.0.0: {} + is-map@2.0.3: {} + + is-module@1.0.0: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + is-number@7.0.0: {} + is-obj@1.0.1: {} + is-obj@2.0.0: {} is-obj@3.0.0: {} @@ -8297,16 +10310,57 @@ snapshots: is-promise@4.0.0: {} + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + is-regexp@1.0.0: {} + is-regexp@3.1.0: {} + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + is-stream@2.0.1: {} is-stream@4.0.1: {} + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.22 + is-unicode-supported@1.3.0: {} is-unicode-supported@2.1.0: {} + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-wsl@2.2.0: dependencies: is-docker: 2.2.1 @@ -8317,6 +10371,8 @@ snapshots: isarray@1.0.0: {} + isarray@2.0.5: {} + isbinaryfile@4.0.10: {} isbinaryfile@5.0.7: {} @@ -8329,6 +10385,10 @@ snapshots: isexe@4.0.0: {} + jackspeak@4.2.3: + dependencies: + '@isaacs/cliui': 9.0.0 + jake@10.9.4: dependencies: async: 3.2.6 @@ -8376,6 +10436,8 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonpointer@5.0.1: {} + katex@0.16.47: dependencies: commander: 8.3.0 @@ -8394,6 +10456,8 @@ snapshots: lazy-val@1.0.5: {} + leven@3.1.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -8538,6 +10602,8 @@ snapshots: lowercase-keys@2.0.0: {} + lru-cache@11.5.2: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -8574,14 +10640,14 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - mdast-util-from-markdown@2.0.3: + mdast-util-from-markdown@2.0.3(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 decode-named-character-reference: 1.3.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 - micromark: 4.0.2 + micromark: 4.0.2(supports-color@7.2.0) micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-decode-string: 2.0.1 micromark-util-normalize-identifier: 2.0.1 @@ -8599,79 +10665,79 @@ snapshots: mdast-util-find-and-replace: 3.0.2 micromark-util-character: 2.1.1 - mdast-util-gfm-footnote@2.1.0: + mdast-util-gfm-footnote@2.1.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: - supports-color - mdast-util-gfm-strikethrough@2.0.0: + mdast-util-gfm-strikethrough@2.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm-table@2.0.0: + mdast-util-gfm-table@2.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm-task-list-item@2.0.0: + mdast-util-gfm-task-list-item@2.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-gfm@3.1.0: + mdast-util-gfm@3.1.0(supports-color@7.2.0): dependencies: - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-gfm-autolink-literal: 2.0.1 - mdast-util-gfm-footnote: 2.1.0 - mdast-util-gfm-strikethrough: 2.0.0 - mdast-util-gfm-table: 2.0.0 - mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-gfm-footnote: 2.1.0(supports-color@7.2.0) + mdast-util-gfm-strikethrough: 2.0.0(supports-color@7.2.0) + mdast-util-gfm-table: 2.0.0(supports-color@7.2.0) + mdast-util-gfm-task-list-item: 2.0.0(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-math@3.0.0: + mdast-util-math@3.0.0(supports-color@7.2.0): dependencies: '@types/hast': 3.0.5 '@types/mdast': 4.0.4 devlop: 1.1.0 longest-streak: 3.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 unist-util-remove-position: 5.0.0 transitivePeerDependencies: - supports-color - mdast-util-mdx-expression@2.0.1: + mdast-util-mdx-expression@2.0.1(supports-color@7.2.0): dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.5 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - mdast-util-mdx-jsx@3.2.0: + mdast-util-mdx-jsx@3.2.0(supports-color@7.2.0): dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.5 @@ -8679,7 +10745,7 @@ snapshots: '@types/unist': 3.0.3 ccount: 2.0.1 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 parse-entities: 4.0.2 stringify-entities: 4.0.4 @@ -8688,13 +10754,13 @@ snapshots: transitivePeerDependencies: - supports-color - mdast-util-mdxjs-esm@2.0.1: + mdast-util-mdxjs-esm@2.0.1(supports-color@7.2.0): dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.5 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -8924,7 +10990,7 @@ snapshots: micromark-util-types@2.0.2: {} - micromark@4.0.2: + micromark@4.0.2(supports-color@7.2.0): dependencies: '@types/debug': 4.1.13 debug: 4.4.3(supports-color@7.2.0) @@ -9078,11 +11144,19 @@ snapshots: object-inspect@1.13.4: {} - object-keys@1.1.1: - optional: true + object-keys@1.1.1: {} object-treeify@1.1.33: {} + object.assign@4.1.7: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + has-symbols: 1.1.0 + object-keys: 1.1.1 + obug@2.1.4: {} on-finished@2.4.1: @@ -9145,6 +11219,13 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.2.0 + own-keys@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + p-cancelable@2.1.1: {} p-limit@2.3.0: @@ -9165,6 +11246,8 @@ snapshots: p-try@2.2.0: {} + package-json-from-dist@1.0.1: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -9206,6 +11289,13 @@ snapshots: path-key@4.0.0: {} + path-parse@1.0.7: {} + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.2 + minipass: 7.1.3 + path-to-regexp@8.4.2: {} pathe@2.0.3: {} @@ -9239,6 +11329,8 @@ snapshots: base64-js: 1.5.1 xmlbuilder: 15.1.1 + possible-typed-array-names@1.1.0: {} + postcss-selector-parser@7.1.5: dependencies: cssesc: 3.0.0 @@ -9261,6 +11353,10 @@ snapshots: prettier@3.9.6: {} + pretty-bytes@5.6.0: {} + + pretty-bytes@6.1.1: {} + pretty-ms@9.3.0: dependencies: parse-ms: 4.0.0 @@ -9332,17 +11428,17 @@ snapshots: react-is@19.2.8: {} - react-markdown@10.1.0(@types/react@19.2.18)(react@19.2.8): + react-markdown@10.1.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0): dependencies: '@types/hast': 3.0.5 '@types/mdast': 4.0.4 '@types/react': 19.2.18 devlop: 1.1.0 - hast-util-to-jsx-runtime: 2.3.6 + hast-util-to-jsx-runtime: 2.3.6(supports-color@7.2.0) html-url-attributes: 3.0.1 mdast-util-to-hast: 13.2.1 react: 19.2.8 - remark-parse: 11.0.0 + remark-parse: 11.0.0(supports-color@7.2.0) remark-rehype: 11.1.2 unified: 11.0.5 unist-util-visit: 5.1.0 @@ -9393,7 +11489,7 @@ snapshots: react@19.2.8: {} - read-binary-file-arch@1.0.6: + read-binary-file-arch@1.0.6(supports-color@7.2.0): dependencies: debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: @@ -9443,6 +11539,23 @@ snapshots: redux@5.0.1: {} + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regenerate-unicode-properties@10.2.2: + dependencies: + regenerate: 1.4.2 + + regenerate@1.4.2: {} + regex-recursion@6.0.2: dependencies: regex-utilities: 2.3.0 @@ -9453,6 +11566,30 @@ snapshots: dependencies: regex-utilities: 2.3.0 + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + regexpu-core@6.4.0: + dependencies: + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.2 + regjsgen: 0.8.0 + regjsparser: 0.13.2 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.1 + + regjsgen@0.8.0: {} + + regjsparser@0.13.2: + dependencies: + jsesc: 3.1.0 + rehype-autolink-headings@7.1.0: dependencies: '@types/hast': 3.0.5 @@ -9486,30 +11623,30 @@ snapshots: mdast-util-newline-to-break: 2.0.0 unified: 11.0.5 - remark-gfm@4.0.1: + remark-gfm@4.0.1(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-gfm: 3.1.0 + mdast-util-gfm: 3.1.0(supports-color@7.2.0) micromark-extension-gfm: 3.0.0 - remark-parse: 11.0.0 + remark-parse: 11.0.0(supports-color@7.2.0) remark-stringify: 11.0.0 unified: 11.0.5 transitivePeerDependencies: - supports-color - remark-math@6.0.0: + remark-math@6.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-math: 3.0.0 + mdast-util-math: 3.0.0(supports-color@7.2.0) micromark-extension-math: 3.1.0 unified: 11.0.5 transitivePeerDependencies: - supports-color - remark-parse@11.0.0: + remark-parse@11.0.0(supports-color@7.2.0): dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) micromark-util-types: 2.0.2 unified: 11.0.5 transitivePeerDependencies: @@ -9543,6 +11680,13 @@ snapshots: resolve-from@4.0.0: {} + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + responselike@2.0.1: dependencies: lowercase-keys: 2.0.0 @@ -9590,7 +11734,39 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.2.3 '@rolldown/binding-win32-x64-msvc': 1.2.3 - router@2.2.0: + rollup@4.62.4: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.62.4 + '@rollup/rollup-android-arm64': 4.62.4 + '@rollup/rollup-darwin-arm64': 4.62.4 + '@rollup/rollup-darwin-x64': 4.62.4 + '@rollup/rollup-freebsd-arm64': 4.62.4 + '@rollup/rollup-freebsd-x64': 4.62.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.4 + '@rollup/rollup-linux-arm-musleabihf': 4.62.4 + '@rollup/rollup-linux-arm64-gnu': 4.62.4 + '@rollup/rollup-linux-arm64-musl': 4.62.4 + '@rollup/rollup-linux-loong64-gnu': 4.62.4 + '@rollup/rollup-linux-loong64-musl': 4.62.4 + '@rollup/rollup-linux-ppc64-gnu': 4.62.4 + '@rollup/rollup-linux-ppc64-musl': 4.62.4 + '@rollup/rollup-linux-riscv64-gnu': 4.62.4 + '@rollup/rollup-linux-riscv64-musl': 4.62.4 + '@rollup/rollup-linux-s390x-gnu': 4.62.4 + '@rollup/rollup-linux-x64-gnu': 4.62.4 + '@rollup/rollup-linux-x64-musl': 4.62.4 + '@rollup/rollup-openbsd-x64': 4.62.4 + '@rollup/rollup-openharmony-arm64': 4.62.4 + '@rollup/rollup-win32-arm64-msvc': 4.62.4 + '@rollup/rollup-win32-ia32-msvc': 4.62.4 + '@rollup/rollup-win32-x64-gnu': 4.62.4 + '@rollup/rollup-win32-x64-msvc': 4.62.4 + fsevents: 2.3.3 + + router@2.2.0(supports-color@7.2.0): dependencies: debug: 4.4.3(supports-color@7.2.0) depd: 2.0.0 @@ -9610,8 +11786,27 @@ snapshots: dependencies: tslib: 2.8.1 + safe-array-concat@1.1.4: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + safe-buffer@5.1.2: {} + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + safer-buffer@2.1.2: {} sanitize-filename@1.6.4: @@ -9637,7 +11832,7 @@ snapshots: semver@7.8.5: {} - send@1.2.1: + send@1.2.1(supports-color@7.2.0): dependencies: debug: 4.4.3(supports-color@7.2.0) encodeurl: 2.0.0 @@ -9658,31 +11853,55 @@ snapshots: type-fest: 0.13.1 optional: true + serialize-javascript@7.1.0: {} + seroval-plugins@1.6.2(seroval@1.6.2): dependencies: seroval: 1.6.2 seroval@1.6.2: {} - serve-static@2.2.1: + serve-static@2.2.1(supports-color@7.2.0): dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 1.2.1 + send: 1.2.1(supports-color@7.2.0) transitivePeerDependencies: - supports-color + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + setprototypeof@1.2.0: {} - shadcn@4.16.2(typescript@6.0.3): + shadcn@4.16.2(supports-color@7.2.0)(typescript@6.0.3): dependencies: - '@babel/core': 7.29.7 + '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/parser': 7.29.8 - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) - '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) '@dotenvx/dotenvx': 1.75.1 - '@modelcontextprotocol/sdk': 1.30.0(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.30.0(supports-color@7.2.0)(zod@3.25.76) '@types/validate-npm-package-name': 4.0.2 browserslist: 4.28.7 commander: 14.0.3 @@ -9772,6 +11991,8 @@ snapshots: sisteransi@1.0.5: {} + smob@1.6.2: {} + sonner@2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: react: 19.2.8 @@ -9793,6 +12014,8 @@ snapshots: source-map@0.6.1: {} + source-map@0.8.0: {} + space-separated-tokens@2.0.2: {} sprintf-js@1.1.3: @@ -9808,6 +12031,11 @@ snapshots: stdin-discarder@0.2.2: {} + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -9820,6 +12048,46 @@ snapshots: get-east-asian-width: 1.6.0 strip-ansi: 7.2.0 + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.1 + + string.prototype.trim@1.2.11: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + has-property-descriptors: 1.0.2 + safe-regex-test: 1.1.0 + + string.prototype.trimend@1.0.10: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -9829,6 +12097,12 @@ snapshots: character-entities-html4: 2.1.0 character-entities-legacy: 3.0.0 + stringify-object@3.3.0: + dependencies: + get-own-enumerable-property-symbols: 3.0.2 + is-obj: 1.0.1 + is-regexp: 1.0.0 + stringify-object@5.0.0: dependencies: get-own-enumerable-keys: 1.0.0 @@ -9845,6 +12119,8 @@ snapshots: strip-bom@3.0.0: {} + strip-comments@2.0.1: {} + strip-final-newline@2.0.0: {} strip-final-newline@4.0.0: {} @@ -9859,7 +12135,7 @@ snapshots: dependencies: inline-style-parser: 0.2.7 - sumchecker@3.0.1: + sumchecker@3.0.1(supports-color@7.2.0): dependencies: debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: @@ -9869,6 +12145,8 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} + systeminformation@5.33.1: {} tailwind-merge@3.6.0: {} @@ -9889,6 +12167,8 @@ snapshots: minizlib: 3.1.0 yallist: 5.0.0 + temp-dir@2.0.0: {} + temp-file@3.4.0: dependencies: async-exit-hook: 2.0.1 @@ -9899,6 +12179,20 @@ snapshots: mkdirp: 0.5.6 rimraf: 2.6.3 + tempy@0.6.0: + dependencies: + is-stream: 2.0.1 + temp-dir: 2.0.0 + type-fest: 0.16.0 + unique-string: 2.0.0 + + terser@5.50.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.18.0 + commander: 2.20.3 + source-map-support: 0.5.21 + tiny-async-pool@1.3.0: dependencies: semver: 5.7.2 @@ -9962,12 +12256,47 @@ snapshots: type-fest@0.13.1: optional: true + type-fest@0.16.0: {} + type-is@2.1.0: dependencies: content-type: 2.0.0 media-typer: 1.1.1 mime-types: 3.0.2 + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.8: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + typed-emitter@2.1.0: optionalDependencies: rxjs: 7.8.2 @@ -9977,23 +12306,12 @@ snapshots: '@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/parser': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - typescript-eslint@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/parser': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) - eslint: 10.8.1(jiti@2.7.0) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - typescript@6.0.3: {} typescript@7.0.2: @@ -10020,6 +12338,13 @@ snapshots: '@typescript/typescript-win32-x64': 7.0.2 optional: true + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + undici-types@7.18.2: {} undici-types@8.3.0: {} @@ -10028,6 +12353,17 @@ snapshots: undici@7.29.0: {} + unicode-canonical-property-names-ecmascript@2.0.1: {} + + unicode-match-property-ecmascript@2.0.0: + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.2.0 + + unicode-match-property-value-ecmascript@2.2.1: {} + + unicode-property-aliases-ecmascript@2.2.0: {} + unicorn-magic@0.3.0: {} unified@11.0.5: @@ -10040,6 +12376,10 @@ snapshots: trough: 2.2.0 vfile: 6.0.3 + unique-string@2.0.0: + dependencies: + crypto-random-string: 2.0.0 + unist-util-find-after@5.0.0: dependencies: '@types/unist': 3.0.3 @@ -10087,6 +12427,8 @@ snapshots: graceful-fs: 4.2.11 node-int64: 0.4.0 + upath@1.2.0: {} + update-browserslist-db@1.3.0(browserslist@4.28.7): dependencies: browserslist: 4.28.7 @@ -10170,7 +12512,18 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0): + vite-plugin-pwa@1.3.0(supports-color@7.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0))(workbox-build@7.4.1(supports-color@7.2.0))(workbox-window@7.4.1): + dependencies: + debug: 4.4.3(supports-color@7.2.0) + pretty-bytes: 6.1.1 + tinyglobby: 0.2.17 + vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) + workbox-build: 7.4.1(supports-color@7.2.0) + workbox-window: 7.4.1 + transitivePeerDependencies: + - supports-color + + vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.5 @@ -10182,12 +12535,13 @@ snapshots: esbuild: 0.28.1 fsevents: 2.3.3 jiti: 2.7.0 + terser: 5.50.0 yaml: 2.9.0 - vitest@4.1.10(@types/node@26.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)): + vitest@4.1.10(@types/node@26.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/mocker': 4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -10204,7 +12558,7 @@ snapshots: tinyexec: 1.3.0 tinyglobby: 0.2.17 tinyrainbow: 3.1.1 - vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0) + vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 26.2.0 @@ -10227,6 +12581,47 @@ snapshots: dependencies: sdp: 3.2.2 + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.2.0 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.22 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.22: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + which@2.0.2: dependencies: isexe: 2.0.0 @@ -10250,6 +12645,119 @@ snapshots: word-wrap@1.2.5: {} + workbox-background-sync@7.4.1: + dependencies: + idb: 7.1.1 + workbox-core: 7.4.1 + + workbox-broadcast-update@7.4.1: + dependencies: + workbox-core: 7.4.1 + + workbox-build@7.4.1(supports-color@7.2.0): + dependencies: + '@apideck/better-ajv-errors': 0.3.7(ajv@8.20.0) + '@babel/core': 7.29.7(supports-color@7.2.0) + '@babel/preset-env': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/runtime': 7.29.7 + '@rollup/plugin-babel': 6.1.0(@babel/core@7.29.7(supports-color@7.2.0))(rollup@4.62.4)(supports-color@7.2.0) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.62.4) + '@rollup/plugin-replace': 6.0.3(rollup@4.62.4) + '@rollup/plugin-terser': 1.0.0(rollup@4.62.4) + '@trickfilm400/rollup-plugin-off-main-thread': 3.0.0-pre1 + ajv: 8.20.0 + common-tags: 1.8.2 + eta: 4.6.0 + fast-json-stable-stringify: 2.1.0 + fs-extra: 9.1.0 + glob: 11.1.0 + pretty-bytes: 5.6.0 + rollup: 4.62.4 + source-map: 0.8.0 + stringify-object: 3.3.0 + strip-comments: 2.0.1 + tempy: 0.6.0 + upath: 1.2.0 + workbox-background-sync: 7.4.1 + workbox-broadcast-update: 7.4.1 + workbox-cacheable-response: 7.4.1 + workbox-core: 7.4.1 + workbox-expiration: 7.4.1 + workbox-google-analytics: 7.4.1 + workbox-navigation-preload: 7.4.1 + workbox-precaching: 7.4.1 + workbox-range-requests: 7.4.1 + workbox-recipes: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 + workbox-streams: 7.4.1 + workbox-sw: 7.4.1 + workbox-window: 7.4.1 + transitivePeerDependencies: + - '@types/babel__core' + - supports-color + + workbox-cacheable-response@7.4.1: + dependencies: + workbox-core: 7.4.1 + + workbox-core@7.4.1: {} + + workbox-expiration@7.4.1: + dependencies: + idb: 7.1.1 + workbox-core: 7.4.1 + + workbox-google-analytics@7.4.1: + dependencies: + workbox-background-sync: 7.4.1 + workbox-core: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 + + workbox-navigation-preload@7.4.1: + dependencies: + workbox-core: 7.4.1 + + workbox-precaching@7.4.1: + dependencies: + workbox-core: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 + + workbox-range-requests@7.4.1: + dependencies: + workbox-core: 7.4.1 + + workbox-recipes@7.4.1: + dependencies: + workbox-cacheable-response: 7.4.1 + workbox-core: 7.4.1 + workbox-expiration: 7.4.1 + workbox-precaching: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 + + workbox-routing@7.4.1: + dependencies: + workbox-core: 7.4.1 + + workbox-strategies@7.4.1: + dependencies: + workbox-core: 7.4.1 + + workbox-streams@7.4.1: + dependencies: + workbox-core: 7.4.1 + workbox-routing: 7.4.1 + + workbox-sw@7.4.1: {} + + workbox-window@7.4.1: + dependencies: + '@types/trusted-types': 2.0.7 + workbox-core: 7.4.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 From caa7d65b8486a38f0e1a279a8c072a256481c925 Mon Sep 17 00:00:00 2001 From: Alois Date: Tue, 18 Aug 2026 21:40:57 +0200 Subject: [PATCH 80/97] feat(pwa): remove install prompt --- .fallowrc.json | 1 + apps/pwa/src/runtime.tsx | 53 +---------------------------------- apps/pwa/src/serviceWorker.ts | 19 +++++++------ 3 files changed, 13 insertions(+), 60 deletions(-) diff --git a/.fallowrc.json b/.fallowrc.json index 022e0cc..ba50fb5 100644 --- a/.fallowrc.json +++ b/.fallowrc.json @@ -3,6 +3,7 @@ "entry": [ "src/index.{ts,tsx,js,jsx}", "src/main.{ts,tsx,js,jsx}", + "apps/pwa/src/serviceWorker.ts", "apps/tauri/render-version.ts", "packages/**/*.test.ts" ], diff --git a/apps/pwa/src/runtime.tsx b/apps/pwa/src/runtime.tsx index d7917cc..21c2556 100644 --- a/apps/pwa/src/runtime.tsx +++ b/apps/pwa/src/runtime.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { toast } from "sonner"; import { setDatabaseEntry } from "@tensamin/shared/indexedDb"; @@ -6,11 +6,6 @@ import { isTauri } from "@tauri-apps/api/core"; import "./style.css"; -type BeforeInstallPromptEvent = Event & { - prompt: () => Promise; - userChoice: Promise<{ outcome: "accepted" | "dismissed" }>; -}; - const launchedFiles: File[] = []; const fileListeners = new Set<(file: File) => void>(); @@ -66,9 +61,6 @@ async function enablePush() { } export default function PwaRuntime() { - const [installPrompt, setInstallPrompt] = - useState(null); - useEffect(() => { if ( isTauri() || @@ -129,16 +121,6 @@ export default function PwaRuntime() { }; }, []); - useEffect(() => { - const handleInstallPrompt = (event: Event) => { - event.preventDefault(); - setInstallPrompt(event as BeforeInstallPromptEvent); - }; - window.addEventListener("beforeinstallprompt", handleInstallPrompt); - return () => - window.removeEventListener("beforeinstallprompt", handleInstallPrompt); - }, []); - useEffect(() => { const launchQueue = ( window as Window & { @@ -158,39 +140,6 @@ export default function PwaRuntime() { }); }, []); - useEffect(() => { - if (!installPrompt) return; - toast("Install Tensamin for a native app experience", { - duration: Infinity, - action: { - label: "Install", - onClick: () => { - void installPrompt.prompt().then(() => installPrompt.userChoice); - setInstallPrompt(null); - }, - }, - }); - }, [installPrompt]); - - useEffect(() => { - const isAppleMobile = /iPad|iPhone|iPod/.test(navigator.userAgent); - if ( - isTauri() || - !isAppleMobile || - isStandalone() || - localStorage.getItem("pwa-ios-install-hint") - ) { - return; - } - localStorage.setItem("pwa-ios-install-hint", "shown"); - toast( - "Install Tensamin from Safari's Share menu to enable background notifications.", - { - duration: 12_000, - }, - ); - }, []); - useEffect(() => { if ( !isStandalone() || diff --git a/apps/pwa/src/serviceWorker.ts b/apps/pwa/src/serviceWorker.ts index de341bb..554ceeb 100644 --- a/apps/pwa/src/serviceWorker.ts +++ b/apps/pwa/src/serviceWorker.ts @@ -34,19 +34,22 @@ function isPushPayload(value: unknown): value is PushPayload { const message = payload.message as Partial | undefined; const secret = payload.secret as Partial | undefined; + const stringValues = [ + payload.sender, + message?.content, + secret?.chatId, + secret?.secretId, + secret?.encryptedSecret, + secret?.kemCiphertext, + secret?.wrappingScheme, + ]; return ( payload.version === 1 && typeof payload.senderId === "number" && Number.isSafeInteger(payload.senderId) && payload.senderId > 0 && - typeof payload.sender === "string" && - typeof message?.content === "string" && - typeof secret?.chatId === "string" && - typeof secret.secretId === "string" && - typeof secret.version === "number" && - typeof secret.encryptedSecret === "string" && - typeof secret.kemCiphertext === "string" && - typeof secret.wrappingScheme === "string" + typeof secret?.version === "number" && + stringValues.every((item) => typeof item === "string") ); } From d0918ff384a356cc50fa5a4bf6db24ae6d7f41c2 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Tue, 18 Aug 2026 20:46:44 +0000 Subject: [PATCH 81/97] (qol): update release flake hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 2b8781f..d91a817 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.11"; - x86_64DebHash = "sha256-E4FGMpCt2ByaN6d+YzglqeA6LbhMOQmPf3UzAj7uZXE="; + x86_64DebHash = "sha256-p/6boNv9uWTHsPTVa3EhGzr41EwRzCY/fJWlj854DVA="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From 57c7ceb27a0513bd887f492960ac22305462c1f1 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Tue, 18 Aug 2026 20:46:45 +0000 Subject: [PATCH 82/97] (qol): update release flake hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 2b8781f..d91a817 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.11"; - x86_64DebHash = "sha256-E4FGMpCt2ByaN6d+YzglqeA6LbhMOQmPf3UzAj7uZXE="; + x86_64DebHash = "sha256-p/6boNv9uWTHsPTVa3EhGzr41EwRzCY/fJWlj854DVA="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From 2a55c87df10b6e5101118f7b5a9c90f416db0fd4 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 20 Aug 2026 17:05:53 +0200 Subject: [PATCH 83/97] [Updt] Mtp 0.3.0 --- .forgejo/workflows/dependency-builds.yml | 12 + apps/tauri/src-tauri/Cargo.lock | 296 +++------- apps/tauri/src-tauri/Cargo.toml | 8 +- apps/tauri/src-tauri/src/main.rs | 3 - apps/tauri/src-tauri/src/mtp_backend.rs | 613 ++++++++++++++++---- apps/web/package.json | 1 + flake.nix | 2 + package.json | 20 +- packages/call/package.json | 1 + packages/call/src/mediaShare/index.ts | 1 - packages/crypto/package.json | 1 + packages/crypto/src/callSecret.ts | 11 +- packages/crypto/src/chatSecret.ts | 11 +- packages/mtp/package.json | 3 +- packages/mtp/src/context.test.tsx | 203 ++++++- packages/mtp/src/context.tsx | 365 ++++++++---- packages/mtp/src/index.ts | 1 + packages/mtp/src/protocolFields.test.ts | 44 ++ packages/mtp/src/protocolFields.ts | 58 ++ packages/mtp/src/requestIds.test.ts | 25 + packages/mtp/src/requestIds.ts | 24 + packages/mtp/src/values.ts | 5 + packages/notifications/src/context.tsx | 12 +- packages/settings/src/layout.tsx | 50 +- packages/settings/src/manifest.ts | 56 +- packages/settings/src/navigation.ts | 31 + packages/settings/src/pages/index.tsx | 2 +- packages/settings/src/sidebar.tsx | 48 ++ pnpm-lock.yaml | 702 +++++++++++++++-------- pnpm-workspace.yaml | 2 +- utils/scripts/build-packages.ts | 9 +- utils/scripts/lint-packages.ts | 9 +- utils/scripts/update-packages.ts | 9 +- 33 files changed, 1839 insertions(+), 799 deletions(-) create mode 100644 packages/mtp/src/protocolFields.test.ts create mode 100644 packages/mtp/src/protocolFields.ts create mode 100644 packages/mtp/src/requestIds.test.ts create mode 100644 packages/mtp/src/requestIds.ts create mode 100644 packages/settings/src/navigation.ts create mode 100644 packages/settings/src/sidebar.tsx diff --git a/.forgejo/workflows/dependency-builds.yml b/.forgejo/workflows/dependency-builds.yml index 709c75b..fdc778f 100644 --- a/.forgejo/workflows/dependency-builds.yml +++ b/.forgejo/workflows/dependency-builds.yml @@ -37,6 +37,18 @@ jobs: - run: nix develop .#electron --command pnpm run build:packages - run: nix develop .#electron --command pnpm run build:desktop + native-mtp: + if: ${{ github.actor == 'rasensprenger' }} + name: Test native MTP + runs-on: nixos + steps: + - run: nix profile add nixpkgs#nodejs_24 + - uses: https://data.forgejo.org/actions/checkout@v4 + with: + persist-credentials: false + - run: git submodule update --init --recursive + - run: nix develop .#electron --command bash -lc 'cd apps/tauri/src-tauri && cargo test' + mobile: if: ${{ github.actor == 'rasensprenger' }} name: Build mobile diff --git a/apps/tauri/src-tauri/Cargo.lock b/apps/tauri/src-tauri/Cargo.lock index b1b1c0b..d404d61 100644 --- a/apps/tauri/src-tauri/Cargo.lock +++ b/apps/tauri/src-tauri/Cargo.lock @@ -674,12 +674,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - [[package]] name = "const-oid" version = "0.10.2" @@ -889,7 +883,6 @@ dependencies = [ "cfg-if", "cpufeatures 0.2.17", "curve25519-dalek-derive", - "digest 0.10.7", "fiat-crypto 0.2.9", "rustc_version", "subtle", @@ -974,25 +967,14 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid 0.9.6", - "pem-rfc7468 0.7.0", - "zeroize", -] - [[package]] name = "der" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a69dedd701da44b0536442edf09c81a64b0ab97a7a4a5e3d1971f00027cbc63d" dependencies = [ - "const-oid 0.10.2", - "pem-rfc7468 1.0.0", + "const-oid", + "pem-rfc7468", "zeroize", ] @@ -1057,7 +1039,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer 0.12.1", - "const-oid 0.10.2", + "const-oid", "crypto-common 0.2.2", "ctutils", ] @@ -1204,38 +1186,14 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8 0.10.2", - "signature 2.2.0", -] - [[package]] name = "ed25519" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" dependencies = [ - "pkcs8 0.11.0", - "signature 3.0.0", -] - -[[package]] -name = "ed25519-dalek" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" -dependencies = [ - "curve25519-dalek 4.1.3", - "ed25519 2.2.3", - "serde", - "sha2 0.10.9", - "subtle", - "zeroize", + "pkcs8", + "signature", ] [[package]] @@ -1245,10 +1203,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de" dependencies = [ "curve25519-dalek 5.0.0", - "ed25519 3.0.0", + "ed25519", "serde", "sha2 0.11.0", - "signature 3.0.0", + "signature", "subtle", "zeroize", ] @@ -2737,14 +2695,14 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "add6b9d92e496f16f4526d68ff29da1483aba4b119baeab8bed3b9e3544a6f3d" dependencies = [ - "const-oid 0.10.2", + "const-oid", "crypto-common 0.2.2", "ctutils", "hybrid-array", "module-lattice", - "pkcs8 0.11.0", + "pkcs8", "shake", - "signature 3.0.0", + "signature", ] [[package]] @@ -2786,72 +2744,50 @@ dependencies = [ [[package]] name = "mtp" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" +version = "0.3.0" +source = "git+https://git.methanium.net/Methanium/mtp.git?rev=a5c8d4f0c898c78351e9d54124886c86e789a22a#a5c8d4f0c898c78351e9d54124886c86e789a22a" dependencies = [ "mtp-client", - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-codec", + "mtp-common", + "mtp-crypto", "mtp-host", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-transport", + "mtp-type-map", "mtp-webserver", ] [[package]] name = "mtp-client" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" +version = "0.3.0" +source = "git+https://git.methanium.net/Methanium/mtp.git?rev=a5c8d4f0c898c78351e9d54124886c86e789a22a#a5c8d4f0c898c78351e9d54124886c86e789a22a" dependencies = [ - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-codec", + "mtp-common", + "mtp-crypto", + "mtp-transport", "rand 0.10.2", "tokio", ] [[package]] name = "mtp-codec" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" +version = "0.3.0" +source = "git+https://git.methanium.net/Methanium/mtp.git?rev=a5c8d4f0c898c78351e9d54124886c86e789a22a#a5c8d4f0c898c78351e9d54124886c86e789a22a" dependencies = [ "base64 0.23.1", "byteorder", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-common", + "mtp-crypto", + "mtp-type-map", "rand 0.10.2", -] - -[[package]] -name = "mtp-codec" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b#b067614a684eb1856bc5db7b3fd82148c036ce6b" -dependencies = [ - "base64 0.23.1", - "byteorder", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", - "mtp-type-map 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", - "rand 0.10.2", -] - -[[package]] -name = "mtp-common" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" -dependencies = [ - "quinn", - "rustls", "thiserror 2.0.19", - "wtransport", ] [[package]] name = "mtp-common" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b#b067614a684eb1856bc5db7b3fd82148c036ce6b" +version = "0.3.0" +source = "git+https://git.methanium.net/Methanium/mtp.git?rev=a5c8d4f0c898c78351e9d54124886c86e789a22a#a5c8d4f0c898c78351e9d54124886c86e789a22a" dependencies = [ "quinn", "rustls", @@ -2861,18 +2797,18 @@ dependencies = [ [[package]] name = "mtp-crypto" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" +version = "0.3.0" +source = "git+https://git.methanium.net/Methanium/mtp.git?rev=a5c8d4f0c898c78351e9d54124886c86e789a22a#a5c8d4f0c898c78351e9d54124886c86e789a22a" dependencies = [ - "base64 0.23.1", + "base64 0.22.1", "chacha20poly1305", - "ed25519-dalek 2.2.0", + "ed25519-dalek", "getrandom 0.4.3", "hkdf", "ml-dsa", "mlkem-tls", "rand 0.10.2", - "rand_core 0.10.1", + "rand_core 0.6.4", "rustls", "serde", "sha2 0.11.0", @@ -2882,89 +2818,45 @@ dependencies = [ ] [[package]] -name = "mtp-crypto" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b#b067614a684eb1856bc5db7b3fd82148c036ce6b" +name = "mtp-host" +version = "0.3.0" +source = "git+https://git.methanium.net/Methanium/mtp.git?rev=a5c8d4f0c898c78351e9d54124886c86e789a22a#a5c8d4f0c898c78351e9d54124886c86e789a22a" dependencies = [ - "base64 0.23.1", - "chacha20poly1305", - "ed25519-dalek 3.0.0", - "getrandom 0.4.3", - "hkdf", - "ml-dsa", + "mtp-codec", + "mtp-common", + "mtp-crypto", + "mtp-transport", "rand 0.10.2", - "rand_core 0.10.1", - "rustls", - "sha2 0.11.0", "thiserror 2.0.19", "tokio", + "tracing", + "wtransport", +] + +[[package]] +name = "mtp-transport" +version = "0.3.0" +source = "git+https://git.methanium.net/Methanium/mtp.git?rev=a5c8d4f0c898c78351e9d54124886c86e789a22a#a5c8d4f0c898c78351e9d54124886c86e789a22a" +dependencies = [ + "async-trait", + "mtp-codec", + "mtp-common", + "mtp-crypto", + "rand 0.10.2", + "rcgen", + "rustls", + "rustls-native-certs", + "sha2 0.11.0", + "tokio", + "tracing", + "wtransport", "zeroize", ] -[[package]] -name = "mtp-host" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" -dependencies = [ - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "rand 0.10.2", - "tokio", - "tracing", - "wtransport", -] - -[[package]] -name = "mtp-transport" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" -dependencies = [ - "async-trait", - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "rcgen", - "rustls", - "rustls-native-certs", - "sha2 0.11.0", - "tokio", - "tracing", - "wtransport", -] - -[[package]] -name = "mtp-transport" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b#b067614a684eb1856bc5db7b3fd82148c036ce6b" -dependencies = [ - "async-trait", - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", - "rcgen", - "rustls", - "rustls-native-certs", - "sha2 0.11.0", - "tokio", - "tracing", - "wtransport", -] - [[package]] name = "mtp-type-map" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" -dependencies = [ - "serde", - "serde_yaml", -] - -[[package]] -name = "mtp-type-map" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b#b067614a684eb1856bc5db7b3fd82148c036ce6b" +version = "0.3.0" +source = "git+https://git.methanium.net/Methanium/mtp.git?rev=a5c8d4f0c898c78351e9d54124886c86e789a22a#a5c8d4f0c898c78351e9d54124886c86e789a22a" dependencies = [ "serde", "serde_yaml", @@ -2972,8 +2864,8 @@ dependencies = [ [[package]] name = "mtp-webserver" -version = "0.2.0" -source = "git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22#7182272e3edb0079d7b74b45b2f62a298d2fee22" +version = "0.3.0" +source = "git+https://git.methanium.net/Methanium/mtp.git?rev=a5c8d4f0c898c78351e9d54124886c86e789a22a#a5c8d4f0c898c78351e9d54124886c86e789a22a" dependencies = [ "async-trait", "bytes", @@ -2984,13 +2876,12 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", - "mtp-codec 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-common 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", - "mtp-crypto 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-codec", + "mtp-common", + "mtp-crypto", "mtp-host", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=7182272e3edb0079d7b74b45b2f62a298d2fee22)", + "mtp-transport", "quinn", - "rand 0.10.2", "rustls", "thiserror 2.0.19", "tokio", @@ -3492,15 +3383,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - [[package]] name = "pem-rfc7468" version = "1.0.0" @@ -3586,24 +3468,14 @@ dependencies = [ "futures-io", ] -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der 0.7.10", - "spki 0.7.3", -] - [[package]] name = "pkcs8" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" dependencies = [ - "der 0.8.1", - "spki 0.8.0", + "der", + "spki", ] [[package]] @@ -4592,15 +4464,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "rand_core 0.6.4", -] - [[package]] name = "signature" version = "3.0.0" @@ -4709,16 +4572,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der 0.7.10", -] - [[package]] name = "spki" version = "0.8.0" @@ -4726,7 +4579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" dependencies = [ "base64ct", - "der 0.8.1", + "der", ] [[package]] @@ -5289,7 +5142,6 @@ dependencies = [ "base64 0.22.1", "jni 0.22.4", "mtp", - "mtp-transport 0.2.0 (git+https://git.methanium.net/methanium/mtp.git?rev=b067614a684eb1856bc5db7b3fd82148c036ce6b)", "reqwest", "serde", "serde_json", diff --git a/apps/tauri/src-tauri/Cargo.toml b/apps/tauri/src-tauri/Cargo.toml index 08a66d5..2a68e95 100644 --- a/apps/tauri/src-tauri/Cargo.toml +++ b/apps/tauri/src-tauri/Cargo.toml @@ -24,8 +24,7 @@ serde_json = "1" base64 = "0.22" reqwest = { version = "0.13", default-features = false, features = ["json", "rustls"] } tokio = { version = "1", features = ["rt-multi-thread", "sync", "time"] } -mtp = { git = "https://git.methanium.net/methanium/mtp.git", rev = "7182272e3edb0079d7b74b45b2f62a298d2fee22", features = ["client", "crypto"] } -mtp-transport = { git = "https://git.methanium.net/methanium/mtp.git", rev = "b067614a684eb1856bc5db7b3fd82148c036ce6b" } +mtp = { git = "https://git.methanium.net/Methanium/mtp.git", rev = "a5c8d4f0c898c78351e9d54124886c86e789a22a", features = ["client", "crypto"] } webpki-root-certs = "1" tauri-plugin-deep-link = "2" tauri-plugin-notification = "2" @@ -36,6 +35,11 @@ version = "2" features = [] default-features = true +[target.'cfg(not(target_os = "android"))'.dependencies.tauri] +version = "2" +features = [] +default-features = true + [target.'cfg(target_os = "android")'.dependencies] jni = "0.22" diff --git a/apps/tauri/src-tauri/src/main.rs b/apps/tauri/src-tauri/src/main.rs index e78a26a..272583a 100644 --- a/apps/tauri/src-tauri/src/main.rs +++ b/apps/tauri/src-tauri/src/main.rs @@ -1,9 +1,6 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] -use lib::log; - fn main() { mobile_lib::run(); - log("Test test 123") } diff --git a/apps/tauri/src-tauri/src/mtp_backend.rs b/apps/tauri/src-tauri/src/mtp_backend.rs index b343337..14365b8 100644 --- a/apps/tauri/src-tauri/src/mtp_backend.rs +++ b/apps/tauri/src-tauri/src/mtp_backend.rs @@ -2,7 +2,7 @@ use std::sync::{ atomic::{AtomicBool, AtomicU64, Ordering}, Arc, Mutex, OnceLock, RwLock, }; -use std::time::Duration; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; use base64::{ engine::general_purpose::{STANDARD, STANDARD_NO_PAD}, @@ -16,6 +16,7 @@ use mtp::crypto::{ use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use tauri::{AppHandle, Emitter}; +use tokio::sync::mpsc; const EVENT_NAME: &str = "mtp://event"; const DISCONNECTED: u8 = 0; @@ -24,6 +25,9 @@ const CONNECTED: u8 = 2; const CHAT_SECRET_SALT: &[u8] = b"tensamin-chat-secret-v1"; const CHAT_MESSAGE_SALT: &[u8] = b"tensamin-chat-message-v1"; const CHAT_SECRET_SCHEME: &str = "mtp-chat-secret-kem-chacha20poly1305-hkdf-sha256-v1"; +const INITIAL_SYNC_TIMEOUT: Duration = Duration::from_secs(30); +const MAX_BUFFERED_INITIAL_FRAMES: usize = 1_000; +const NOTIFICATION_QUEUE_CAPACITY: usize = 32; #[cfg(target_os = "android")] const ROOT_YE_PEM: &[u8] = b"-----BEGIN CERTIFICATE-----\n\ MIIB2TCCAWCgAwIBAgIRAKQCa6LvbHwg1AR+XmWmk4AwCgYIKoZIzj0EAwMwLjEL\n\ @@ -95,7 +99,7 @@ enum MtpEvent { pub struct MtpManager { runtime: tokio::runtime::Runtime, config: RwLock>, - connection: RwLock>>, + connection: RwLock>>, snapshot: RwLock, generation: AtomicU64, enabled: AtomicBool, @@ -104,6 +108,46 @@ pub struct MtpManager { start_lock: Mutex<()>, } +struct RequestIdAllocator { + next: AtomicU64, +} + +impl RequestIdAllocator { + fn new() -> Self { + Self { + next: AtomicU64::new(1), + } + } + + fn next(&self) -> Result { + let value = self.next.fetch_add(1, Ordering::Relaxed); + u32::try_from(value) + .map_err(|_| "MTP request ID space exhausted for this connection".to_string()) + } +} + +struct ManagedConnection { + mtp: Arc, + request_ids: RequestIdAllocator, +} + +impl ManagedConnection { + async fn next_request_id(&self) -> Result { + let id = self.request_ids.next(); + if id.is_err() { + self.mtp.sender.close().await; + } + id + } +} + +struct PreparedConnection { + connection: MTPConnection, + request_ids: RequestIdAllocator, + initial_state: Value, + buffered_frames: Vec, +} + static MANAGER: OnceLock = OnceLock::new(); pub fn manager() -> &'static MtpManager { @@ -149,7 +193,7 @@ impl MtpManager { .take() { self.runtime - .spawn(async move { connection.sender.close().await }); + .spawn(async move { connection.mtp.sender.close().await }); } self.set_snapshot(MtpSnapshot { generation, @@ -171,7 +215,7 @@ impl MtpManager { .take() { self.runtime - .spawn(async move { connection.sender.close().await }); + .spawn(async move { connection.mtp.sender.close().await }); } self.set_snapshot(MtpSnapshot { generation: self.generation.load(Ordering::SeqCst), @@ -231,20 +275,16 @@ impl MtpManager { self.enabled.load(Ordering::SeqCst) && self.generation.load(Ordering::SeqCst) == generation } - async fn request( - &self, - type_name: &str, - data: Value, - id: Option, - ) -> Result { + async fn request(&self, type_name: &str, data: Value) -> Result { let connection = self .connection .read() .map_err(|_| "MTP connection lock is unavailable")? .clone() .ok_or_else(|| "MTP is not connected".to_string())?; - let request = json_to_frame(type_name, data, id)?; + let request = json_to_frame(type_name, data, connection.next_request_id().await?)?; let response = connection + .mtp .request(&request, None) .await .map_err(|error| error.to_string())?; @@ -261,9 +301,12 @@ async fn supervise(generation: u64) { manager.log(2, "Starting native MTP connection", None); android_status("Connecting"); match connect(&config).await { - Ok((connection, state)) => { + Ok(prepared) => { delay = Duration::from_secs(1); - let connection = Arc::new(connection); + let connection = Arc::new(ManagedConnection { + mtp: Arc::new(prepared.connection), + request_ids: prepared.request_ids, + }); let stale = { let _guard = manager.start_lock.lock().expect("start lock poisoned"); let mut current = manager @@ -279,22 +322,47 @@ async fn supervise(generation: u64) { generation, ready_state: CONNECTED, identified: true, - state: Some(state), + state: Some(prepared.initial_state), error: None, }); false } }; if stale { - connection.sender.close().await; + connection.mtp.sender.close().await; break; } android_status("Connected"); manager.log(2, "Native MTP connection established", None); + let (notification_tx, mut notification_rx) = + mpsc::channel(NOTIFICATION_QUEUE_CAPACITY); + let notification_connection = connection.clone(); + let notification_config = config.clone(); + let notification_worker = tokio::spawn(async move { + while let Some(frame) = notification_rx.recv().await { + if !manager().is_current(generation) { + break; + } + if let Err(error) = notify_message( + ¬ification_config, + notification_connection.clone(), + &frame, + ) + .await + { + eprintln!("failed to create background message notification: {error}"); + } + } + }); + + for frame in prepared.buffered_frames { + handle_push(generation, ¬ification_tx, frame).await; + } + while manager.is_current(generation) { - match connection.receive().await { - Ok(frame) => handle_push(generation, connection.clone(), frame).await, + match connection.mtp.receive().await { + Ok(frame) => handle_push(generation, ¬ification_tx, frame).await, Err(error) => { let _guard = manager.start_lock.lock().expect("start lock poisoned"); if manager.is_current(generation) { @@ -310,6 +378,13 @@ async fn supervise(generation: u64) { } } } + drop(notification_tx); + notification_worker.abort(); + if let Err(error) = notification_worker.await { + if !error.is_cancelled() { + eprintln!("background notification worker failed: {error}"); + } + } let mut current = manager .connection .write() @@ -339,12 +414,21 @@ async fn supervise(generation: u64) { break; } android_status("Reconnecting"); - tokio::time::sleep(delay).await; + tokio::time::sleep(jittered_retry_delay(delay)).await; delay = (delay * 2).min(Duration::from_secs(60)); } } -async fn connect(config: &MtpConfig) -> Result<(MTPConnection, Value), String> { +fn jittered_retry_delay(delay: Duration) -> Duration { + let entropy = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|duration| duration.subsec_nanos()) + .unwrap_or_default(); + let percent = 80 + entropy % 41; + delay.mul_f64(percent as f64 / 100.0) +} + +async fn connect(config: &MtpConfig) -> Result { let (url, public_key) = resolve_endpoint(config) .await .map_err(|error| format!("endpoint discovery failed: {error}"))?; @@ -381,39 +465,10 @@ async fn connect(config: &MtpConfig) -> Result<(MTPConnection, Value), String> { .map_err(|error| format!("transport authentication failed: {error}"))?; manager().log(2, "Native MTP authentication completed", None); - let connected = CommunicationValue::new(CommunicationType::ClientConnected) - .add_typed_default( - DataType::SessionId, - DataValue::UnsignedNumber(current_millis() as u128), - ) - .add_typed_default(DataType::VersionNumber, DataValue::UnsignedNumber(0)) - .add_typed_default(DataType::CacheValid, DataValue::BoolFalse) - .add_typed_default(DataType::CacheSchemaVersion, DataValue::UnsignedNumber(0)); - let state = tokio::time::timeout( - Duration::from_secs(30), - connection.request(&connected, None), - ) - .await - .map_err(|_| "initial state synchronization timed out".to_string())? - .map_err(|error| format!("initial state synchronization failed: {error}"))?; - if !state.is_type(CommunicationType::ClientStateSync) { - return Err(format!( - "expected ClientStateSync, received {}", - state.get_type_name().unwrap_or("unknown") - )); - } - let session_id = state - .get_data(DataType::SessionId) - .as_number() - .ok_or("ClientStateSync omitted SessionId")?; - let version = state - .get_data(DataType::VersionNumber) - .as_number() - .ok_or("ClientStateSync omitted VersionNumber")?; - let ack = CommunicationValue::new(CommunicationType::ClientStateAck) - .add_typed_default(DataType::SessionId, number_to_data(session_id)) - .add_typed_default(DataType::VersionNumber, number_to_data(version)); - let response = tokio::time::timeout(Duration::from_secs(30), connection.request(&ack, None)) + let (state, buffered_frames) = await_initial_state(&connection).await?; + let request_ids = RequestIdAllocator::new(); + let (initial_state, ack) = prepare_initial_state_ack(&state, &request_ids)?; + let response = tokio::time::timeout(INITIAL_SYNC_TIMEOUT, connection.request(&ack, None)) .await .map_err(|_| "state acknowledgement timed out".to_string())? .map_err(|error| format!("state acknowledgement failed: {error}"))?; @@ -423,7 +478,182 @@ async fn connect(config: &MtpConfig) -> Result<(MTPConnection, Value), String> { { return Err(format!("ClientStateAck failed: {response}")); } - Ok((connection, frame_data_to_json(&state)?)) + Ok(PreparedConnection { + connection, + request_ids, + initial_state, + buffered_frames, + }) +} + +fn prepare_initial_state_ack( + state: &CommunicationValue, + request_ids: &RequestIdAllocator, +) -> Result<(Value, CommunicationValue), String> { + let initial_state = frame_data_to_json(state)?; + validate_client_state_sync(&initial_state)?; + let data = initial_state + .as_object() + .ok_or("ClientStateSync payload is not an object")?; + let session_id = required_integer(data, "SessionId")?; + let version = required_integer(data, "VersionNumber")?; + let ack = CommunicationValue::new(CommunicationType::ClientStateAck) + .with_id(request_ids.next()?) + .add_typed_default(DataType::SessionId, number_to_data(session_id)) + .add_typed_default(DataType::VersionNumber, number_to_data(version)); + Ok((initial_state, ack)) +} + +fn validate_client_state_sync(state: &Value) -> Result<(), String> { + let data = state + .as_object() + .ok_or("ClientStateSync payload is not an object")?; + if required_integer(data, "SessionId")? <= 0 { + return Err("ClientStateSync SessionId must be a positive integer".into()); + } + for field in ["VersionNumber", "CacheSchemaVersion"] { + if required_integer(data, field)? < 0 { + return Err(format!("ClientStateSync {field} must be nonnegative")); + } + } + match data.get("SyncMode").and_then(Value::as_str) { + Some("full" | "delta") => {} + _ => return Err("ClientStateSync SyncMode must be 'full' or 'delta'".into()), + } + for field in ["Contacts", "Communities", "Calls", "Messages"] { + if !data.get(field).is_some_and(Value::is_array) { + return Err(format!("ClientStateSync {field} must be an array")); + } + } + for field in ["DeletedMessageIds", "DeletedContactIds"] { + if let Some(value) = data.get(field) { + let values = value + .as_array() + .ok_or_else(|| format!("ClientStateSync {field} must be an array"))?; + if values.iter().any(|value| !value.is_number()) { + return Err(format!("ClientStateSync {field} must contain numbers")); + } + } + } + validate_object_array(data, "Communities", |_| Ok(()))?; + validate_object_array(data, "Contacts", validate_contact)?; + validate_object_array(data, "Calls", validate_call)?; + validate_object_array(data, "Messages", validate_message)?; + Ok(()) +} + +fn validate_object_array( + data: &Map, + field: &str, + validate: impl Fn(&Map) -> Result<(), String>, +) -> Result<(), String> { + let values = data + .get(field) + .and_then(Value::as_array) + .ok_or_else(|| format!("ClientStateSync {field} must be an array"))?; + for value in values { + let object = value + .as_object() + .ok_or_else(|| format!("ClientStateSync {field} entries must be objects"))?; + validate(object)?; + } + Ok(()) +} + +fn validate_contact(contact: &Map) -> Result<(), String> { + if !contact.get("UserId").is_some_and(Value::is_number) { + return Err("ClientStateSync contact omitted numeric UserId".into()); + } + if let Some(messages) = contact.get("Messages") { + let messages = messages + .as_array() + .ok_or("ClientStateSync contact Messages must be an array")?; + for message in messages { + validate_message( + message + .as_object() + .ok_or("ClientStateSync contact message must be an object")?, + )?; + } + } + Ok(()) +} + +fn validate_call(call: &Map) -> Result<(), String> { + if !call.get("CallId").is_some_and(Value::is_string) { + return Err("ClientStateSync call omitted string CallId".into()); + } + let members = call + .get("CallMembers") + .and_then(Value::as_array) + .ok_or("ClientStateSync call omitted CallMembers array")?; + if members.iter().any(|member| !member.is_number()) { + return Err("ClientStateSync CallMembers must contain numbers".into()); + } + Ok(()) +} + +fn validate_message(message: &Map) -> Result<(), String> { + for field in ["SenderId", "SendTime"] { + if !message.get(field).is_some_and(Value::is_number) { + return Err(format!("ClientStateSync message omitted numeric {field}")); + } + } + let content = message + .get("Content") + .and_then(Value::as_str) + .ok_or("ClientStateSync message omitted string Content")?; + STANDARD + .decode(content) + .or_else(|_| STANDARD_NO_PAD.decode(content)) + .map_err(|_| "ClientStateSync message Content must be base64".to_string())?; + if let Some(state) = message.get("MessageState") { + match state.as_str() { + Some("read" | "received" | "sent" | "sending" | "awaiting") => {} + _ => return Err("ClientStateSync message has invalid MessageState".into()), + } + } + Ok(()) +} + +fn required_integer(data: &Map, field: &str) -> Result { + let value = data + .get(field) + .ok_or_else(|| format!("ClientStateSync omitted {field}"))?; + if let Some(value) = value.as_i64() { + return Ok(value as i128); + } + value + .as_u64() + .map(|value| value as i128) + .ok_or_else(|| format!("ClientStateSync {field} must be an integer")) +} + +async fn await_initial_state( + connection: &MTPConnection, +) -> Result<(CommunicationValue, Vec), String> { + let mut buffered = Vec::new(); + let deadline = tokio::time::Instant::now() + INITIAL_SYNC_TIMEOUT; + + loop { + let frame = tokio::time::timeout_at(deadline, connection.receive()) + .await + .map_err(|_| "initial state synchronization timed out".to_string())? + .map_err(|error| format!("initial state synchronization failed: {error}"))?; + + if frame.is_type(CommunicationType::ErrorNoIota) { + return Err("No Iota is currently connected".into()); + } + + if frame.is_type(CommunicationType::ClientStateSync) { + return Ok((frame, buffered)); + } + + if buffered.len() == MAX_BUFFERED_INITIAL_FRAMES { + return Err("initial state synchronization buffered too many frames".into()); + } + buffered.push(frame); + } } async fn resolve_endpoint(config: &MtpConfig) -> Result<(String, String), String> { @@ -465,7 +695,11 @@ async fn resolve_endpoint(config: &MtpConfig) -> Result<(String, String), String )) } -async fn handle_push(generation: u64, connection: Arc, frame: CommunicationValue) { +async fn handle_push( + generation: u64, + notification_tx: &mpsc::Sender, + frame: CommunicationValue, +) { let manager = manager(); if let Ok(message) = frame_to_json(&frame) { manager.emit(MtpEvent::Message { @@ -478,7 +712,7 @@ async fn handle_push(generation: u64, connection: Arc, frame: Com { if let Some(partner_id) = frame .get_data(DataType::ChatPartnerId) - .as_number() + .and_then(DataValue::as_number) .and_then(|value| u64::try_from(value).ok()) { if let Err(error) = android_cancel_notification(partner_id) { @@ -487,40 +721,39 @@ async fn handle_push(generation: u64, connection: Arc, frame: Com } } if frame.is_type(CommunicationType::MessageLive) && !manager.ui_visible.load(Ordering::SeqCst) { - if let Err(error) = notify_message(connection, &frame).await { - eprintln!("failed to create background message notification: {error}"); + if notification_tx.try_send(frame).is_err() { + eprintln!("background message notification queue is full"); } } } async fn notify_message( - connection: Arc, + config: &MtpConfig, + connection: Arc, frame: &CommunicationValue, ) -> Result<(), String> { let sender_id = frame .get_data(DataType::SenderId) - .as_number() + .and_then(DataValue::as_number) .and_then(|value| u64::try_from(value).ok()) .ok_or("MessageLive omitted SenderId")?; - let message = frame.get_data(DataType::Message); - let content = container_value(message, DataType::Content) + let message = frame + .get_data(DataType::Message) + .ok_or("MessageLive omitted Message")?; + let content = container_value(message, DataType::AppContent) .and_then(DataValue::as_str) .ok_or("MessageLive omitted Content")?; - let config = manager() - .config - .read() - .expect("config lock poisoned") - .clone() - .ok_or("missing config")?; let keyring_bytes = decode_browser_base64(&config.keyring)?; let keyring = Keyring::from_bytes(&keyring_bytes).map_err(|error| error.to_string())?; let chat_id = derive_chat_id(config.user_id, sender_id); let secret_id = format!("chat:{chat_id}:main"); let secret_request = CommunicationValue::new(CommunicationType::GetChatSecret) + .with_id(connection.next_request_id().await?) .add_typed_default(DataType::UserId, DataValue::Str(config.user_id.to_string())) .add_typed_default(DataType::ChatId, DataValue::Str(chat_id.clone())) .add_typed_default(DataType::SecretId, DataValue::Str(secret_id.clone())); let secret = connection + .mtp .request(&secret_request, None) .await .map_err(|error| error.to_string())?; @@ -532,7 +765,7 @@ async fn notify_message( } let version = secret .get_data(DataType::VersionNumber) - .as_number() + .and_then(DataValue::as_number) .ok_or("missing secret version")?; let encrypted_secret = secret .get_bytes(DataType::EncryptedSecret) @@ -560,11 +793,14 @@ async fn notify_message( .decrypt(&ciphertext, b"") .map_err(|error| error.to_string())?; - let user_request = CommunicationValue::new(CommunicationType::GetUserData).add_typed_default( - DataType::UserId, - DataValue::UnsignedNumber(sender_id as u128), - ); + let user_request = CommunicationValue::new(CommunicationType::GetUserData) + .with_id(connection.next_request_id().await?) + .add_typed_default( + DataType::UserId, + DataValue::UnsignedNumber(sender_id as u128), + ); let user = connection + .mtp .request(&user_request, None) .await .map_err(|error| error.to_string())?; @@ -652,24 +888,42 @@ fn container_value(value: &DataValue, field: DataType) -> Option<&DataValue> { value.get_field(id) } -fn json_to_frame( - type_name: &str, - data: Value, - id: Option, -) -> Result { +fn wire_field_name(name: &str) -> &str { + match name { + "Content" => "AppContent", + "CreatedAt" => "AppCreatedAt", + "MessageId" => "AppMessageId", + _ => name, + } +} + +fn application_field_name(name: &str) -> &str { + match name { + "AppContent" => "Content", + "AppCreatedAt" => "CreatedAt", + "AppMessageId" => "MessageId", + _ => name, + } +} + +fn json_to_frame(type_name: &str, data: Value, id: u32) -> Result { let comm_type = CommunicationType::from_name(type_name) .ok_or_else(|| format!("unknown communication type: {type_name}"))?; - let mut frame = CommunicationValue::new(comm_type); - if let Some(id) = id { - frame = frame.with_id(id); - } + let mut frame = CommunicationValue::new(comm_type).with_id(id); let Value::Object(fields) = data else { return Err("MTP request data must be an object".into()); }; + let mut translated_fields = std::collections::HashSet::::with_capacity(fields.len()); for (name, value) in fields { + let wire_name = wire_field_name(&name).to_owned(); + if !translated_fields.insert(wire_name.clone()) { + return Err(format!( + "duplicate MTP field after translation: {wire_name}" + )); + } let data_type = - DataType::from_name(&name).ok_or_else(|| format!("unknown data type: {name}"))?; - frame = frame.add_typed_default(data_type, json_to_data(&name, value)?); + DataType::from_name(&wire_name).ok_or_else(|| format!("unknown data type: {name}"))?; + frame = frame.add_typed_default(data_type, json_to_data(&wire_name, value)?); } Ok(frame) } @@ -707,13 +961,21 @@ fn json_to_data(field: &str, value: Value) -> Result { ), Value::Object(fields) => { let mut entries = Vec::with_capacity(fields.len()); + let mut translated_fields = + std::collections::HashSet::::with_capacity(fields.len()); for (name, value) in fields { - let data_type = DataType::from_name(&name) + let wire_name = wire_field_name(&name).to_owned(); + if !translated_fields.insert(wire_name.clone()) { + return Err(format!( + "duplicate MTP field after translation: {wire_name}" + )); + } + let data_type = DataType::from_name(&wire_name) .ok_or_else(|| format!("unknown nested data type: {name}"))?; let id = data_type .try_to_id(&TypeMap::latest()) .ok_or_else(|| format!("unmapped data type: {name}"))?; - entries.push((id, json_to_data(&name, value)?)); + entries.push((id, json_to_data(&wire_name, value)?)); } DataValue::Container(entries) } @@ -737,8 +999,8 @@ fn is_bytes_field(field: &str) -> bool { fn frame_to_json(frame: &CommunicationValue) -> Result { let mut result = Map::new(); - if frame.get_id() != 0 { - result.insert("id".into(), Value::from(frame.get_id())); + if let Some(id) = frame.id() { + result.insert("id".into(), Value::from(id)); } result.insert( "type".into(), @@ -751,11 +1013,20 @@ fn frame_to_json(frame: &CommunicationValue) -> Result { fn frame_data_to_json(frame: &CommunicationValue) -> Result { let map = frame.type_map().cloned().unwrap_or_else(TypeMap::latest); let mut result = Map::new(); - for (id, value) in frame.data() { + let entries = frame + .data() + .ok_or("MTP frame payload is not a data container")?; + for (id, value) in entries { let name = map .data_type_name(id.0) .ok_or_else(|| format!("unknown data type id: {}", id.0))?; - result.insert(name.to_owned(), data_to_json(value, &map)?); + let application_name = application_field_name(name); + if result.contains_key(application_name) { + return Err(format!( + "duplicate MTP field after translation: {application_name}" + )); + } + result.insert(application_name.to_owned(), data_to_json(value, &map)?); } Ok(Value::Object(result)) } @@ -786,7 +1057,13 @@ fn data_to_json(value: &DataValue, map: &TypeMap) -> Result { let name = map .data_type_name(id.0) .ok_or_else(|| format!("unknown nested data type id: {}", id.0))?; - object.insert(name.to_owned(), data_to_json(value, map)?); + let application_name = application_field_name(name); + if object.contains_key(application_name) { + return Err(format!( + "duplicate MTP field after translation: {application_name}" + )); + } + object.insert(application_name.to_owned(), data_to_json(value, map)?); } Value::Object(object) } @@ -801,16 +1078,15 @@ fn number_to_json(value: i128) -> Result { .map_err(|_| "number exceeds JSON range".into()) } -fn current_millis() -> u64 { - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap_or_default() - .as_millis() as u64 -} - #[cfg(test)] mod tests { - use super::{decode_browser_base64, decode_sdk_bytes}; + use mtp::codec::{CommunicationType, CommunicationValue, DataType, DataValue}; + use serde_json::json; + + use super::{ + container_value, decode_browser_base64, decode_sdk_bytes, frame_to_json, + jittered_retry_delay, json_to_frame, prepare_initial_state_ack, RequestIdAllocator, + }; #[test] fn browser_base64_accepts_file_whitespace_and_missing_padding() { @@ -823,11 +1099,148 @@ mod tests { assert_eq!(decode_sdk_bytes("0x01:02-ff").unwrap(), [1, 2, 255]); assert_eq!(decode_sdk_bytes("AQI=").unwrap(), [1, 2]); } + + #[test] + fn request_ids_are_nonzero_and_monotonic() { + let ids = RequestIdAllocator::new(); + + assert_eq!(ids.next().unwrap(), 1); + assert_eq!(ids.next().unwrap(), 2); + } + + #[test] + fn retry_jitter_stays_within_policy_bounds() { + let delay = jittered_retry_delay(std::time::Duration::from_secs(10)); + + assert!(delay >= std::time::Duration::from_secs(8)); + assert!(delay <= std::time::Duration::from_secs(12)); + } + + #[test] + fn json_content_uses_app_content_wire_type() { + let frame = json_to_frame( + "MessageEdit", + json!({ + "Content": "ciphertext", + "ChatPartnerId": 42, + "SendTime": 10, + }), + 1, + ) + .unwrap(); + + assert_eq!( + frame + .get_data(DataType::AppContent) + .and_then(DataValue::as_str), + Some("ciphertext") + ); + } + + #[test] + fn nested_json_content_uses_app_content_wire_type() { + let frame = json_to_frame( + "MessageEdit", + json!({ + "Message": { "Content": "ciphertext" }, + }), + 1, + ) + .unwrap(); + let message = frame.get_data(DataType::Message).unwrap(); + + assert_eq!( + container_value(message, DataType::AppContent).and_then(DataValue::as_str), + Some("ciphertext") + ); + } + + #[test] + fn app_content_is_exposed_as_content_to_frontend() { + let frame = CommunicationValue::new(CommunicationType::MessageEditLive) + .with_id(1) + .add_typed_default(DataType::AppContent, DataValue::Str("ciphertext".into())); + + let json = frame_to_json(&frame).unwrap(); + + assert_eq!(json["data"]["Content"], "ciphertext"); + assert!(json["data"].get("AppContent").is_none()); + } + + #[test] + fn translated_field_collisions_are_rejected() { + assert!(json_to_frame( + "MessageEdit", + json!({ "Content": "a", "AppContent": "b" }), + 1, + ) + .is_err()); + } + + fn valid_initial_state() -> CommunicationValue { + CommunicationValue::new(CommunicationType::ClientStateSync) + .add_typed_default(DataType::SessionId, DataValue::UnsignedNumber(1)) + .add_typed_default(DataType::VersionNumber, DataValue::UnsignedNumber(0)) + .add_typed_default(DataType::CacheSchemaVersion, DataValue::UnsignedNumber(0)) + .add_typed_default(DataType::SyncMode, DataValue::Str("full".into())) + .add_typed_default(DataType::Contacts, DataValue::Array(vec![])) + .add_typed_default(DataType::Communities, DataValue::Array(vec![])) + .add_typed_default(DataType::Calls, DataValue::Array(vec![])) + .add_typed_default(DataType::Messages, DataValue::Array(vec![])) + } + + #[test] + fn valid_initial_state_is_prepared_before_ack() { + let ids = RequestIdAllocator::new(); + let (state, ack) = prepare_initial_state_ack(&valid_initial_state(), &ids).unwrap(); + + assert_eq!(state["SyncMode"], "full"); + assert!(ack.is_type(CommunicationType::ClientStateAck)); + assert_eq!(ack.id(), Some(1)); + } + + #[test] + fn malformed_initial_state_does_not_prepare_ack() { + let ids = RequestIdAllocator::new(); + let malformed = valid_initial_state() + .add_typed_default(DataType::SyncMode, DataValue::Str("invalid".into())); + + assert!(prepare_initial_state_ack(&malformed, &ids).is_err()); + assert_eq!( + ids.next().unwrap(), + 1, + "no acknowledgement ID was allocated" + ); + } + + #[test] + fn malformed_nested_initial_state_does_not_prepare_ack() { + let ids = RequestIdAllocator::new(); + let malformed = CommunicationValue::new(CommunicationType::ClientStateSync) + .add_typed_default(DataType::SessionId, DataValue::UnsignedNumber(1)) + .add_typed_default(DataType::VersionNumber, DataValue::UnsignedNumber(0)) + .add_typed_default(DataType::CacheSchemaVersion, DataValue::UnsignedNumber(0)) + .add_typed_default(DataType::SyncMode, DataValue::Str("full".into())) + .add_typed_default( + DataType::Contacts, + DataValue::Array(vec![DataValue::Container(vec![])]), + ) + .add_typed_default(DataType::Communities, DataValue::Array(vec![])) + .add_typed_default(DataType::Calls, DataValue::Array(vec![])) + .add_typed_default(DataType::Messages, DataValue::Array(vec![])); + + assert!(prepare_initial_state_ack(&malformed, &ids).is_err()); + assert_eq!( + ids.next().unwrap(), + 1, + "no acknowledgement ID was allocated" + ); + } } #[tauri::command] -pub async fn mtp_request(type_name: String, data: Value, id: Option) -> Result { - manager().request(&type_name, data, id).await +pub async fn mtp_request(type_name: String, data: Value) -> Result { + manager().request(&type_name, data).await } #[tauri::command] diff --git a/apps/web/package.json b/apps/web/package.json index f608fcb..a6b3951 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -55,6 +55,7 @@ "esbuild": "^0.28.1", "eslint": "^10.8.0", "globals": "^17.9.0", + "mtp": "*", "typescript": "~6.0.3", "typescript-eslint": "^8.66.0", "vite": "^8.2.1" diff --git a/flake.nix b/flake.nix index d91a817..6a29551 100644 --- a/flake.nix +++ b/flake.nix @@ -63,6 +63,7 @@ pipewire systemd wayland + webkitgtk_4_1 libX11 libXScrnSaver libXcomposite @@ -184,6 +185,7 @@ pipewire systemd wayland + webkitgtk_4_1 libX11 libXScrnSaver libXcomposite diff --git a/package.json b/package.json index 05856f5..051f699 100644 --- a/package.json +++ b/package.json @@ -29,22 +29,22 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@types/node": "^26.1.2", + "@types/node": "^26.2.0", "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", - "@typescript-eslint/parser": "^8.66.0", - "eslint": "^10.8.0", + "@typescript-eslint/parser": "^8.67.0", + "eslint": "^10.8.1", "eslint-plugin-react-hooks": "^7.1.1", - "fallow": "^3.14.0", - "globals": "^17.9.0", + "fallow": "^3.17.0", + "globals": "^17.11.0", "prettier": "^3.9.6", "typescript": "^6.0.3", - "typescript-eslint": "^8.66.0", - "vitest": "^4.1.10" + "typescript-eslint": "^8.67.0", + "vitest": "^4.1.11" }, "dependencies": { - "@methanium/ui": "*", - "mtp": "*", - "sonner": "^2.0.7" + "@methanium/ui": "https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz", + "mtp": "https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz", + "sonner": "^2.0.8" } } diff --git a/packages/call/package.json b/packages/call/package.json index d4f7c10..7171f50 100644 --- a/packages/call/package.json +++ b/packages/call/package.json @@ -28,6 +28,7 @@ "deepfilternet3-noise-filter": "1.3.0", "livekit-client": "^2.21.0", "lucide-react": "^1.29.0", + "mtp": "*", "react": "^19.2.8", "react-dom": "^19.2.8", "recharts": "^3.10.1", diff --git a/packages/call/src/mediaShare/index.ts b/packages/call/src/mediaShare/index.ts index 6d2c47f..9706d4d 100644 --- a/packages/call/src/mediaShare/index.ts +++ b/packages/call/src/mediaShare/index.ts @@ -19,7 +19,6 @@ export function getMediaShareAdapter(): MediaShareAdapter { export type { MediaShareAdapter, - MediaShareCapabilities, MediaShareKind, MediaShareRequest, MediaShareSession, diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 62580df..2b40fdf 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -15,6 +15,7 @@ "build": "tsc -p tsconfig.json --noEmit" }, "dependencies": { + "mtp": "*", "react": "^19.2.8", "react-dom": "^19.2.8" } diff --git a/packages/crypto/src/callSecret.ts b/packages/crypto/src/callSecret.ts index 97ef318..556d131 100644 --- a/packages/crypto/src/callSecret.ts +++ b/packages/crypto/src/callSecret.ts @@ -13,11 +13,13 @@ export function deriveCallSecretId(callId: string): string { } export function ownKemPublicKeyFromKeyring(keyring: string): Uint8Array { - return crypto.keyringToKeys(keyring).kemPublicKey; + return crypto.keyringToKeys({ value: keyring, encoding: "base64" }) + .kemPublicKey; } export function kemPublicKeyFromPublicKeyBundle(publicKey: string): Uint8Array { - return crypto.publicKeyBundleToKeys(publicKey).kemPublicKey; + return crypto.publicKeyBundleToKeys({ value: publicKey, encoding: "base64" }) + .kemPublicKey; } export async function wrapCallSecret(args: { @@ -72,7 +74,10 @@ export async function unwrapCallSecret(args: { ); } - const ownKeys = crypto.keyringToKeys(args.keyring); + const ownKeys = crypto.keyringToKeys({ + value: args.keyring, + encoding: "base64", + }); const sharedSecret = crypto.decapsulate( ownKeys.kemSecretKey, args.kemCiphertext, diff --git a/packages/crypto/src/chatSecret.ts b/packages/crypto/src/chatSecret.ts index e6e836c..cbac59a 100644 --- a/packages/crypto/src/chatSecret.ts +++ b/packages/crypto/src/chatSecret.ts @@ -23,11 +23,13 @@ export function randomChatSecret(): Uint8Array { } export function ownKemPublicKeyFromKeyring(keyring: string): Uint8Array { - return crypto.keyringToKeys(keyring).kemPublicKey; + return crypto.keyringToKeys({ value: keyring, encoding: "base64" }) + .kemPublicKey; } export function kemPublicKeyFromPublicKeyBundle(publicKey: string): Uint8Array { - return crypto.publicKeyBundleToKeys(publicKey).kemPublicKey; + return crypto.publicKeyBundleToKeys({ value: publicKey, encoding: "base64" }) + .kemPublicKey; } export async function wrapChatSecret(args: { @@ -79,7 +81,10 @@ export async function unwrapChatSecret(args: { ); } - const ownKeys = crypto.keyringToKeys(args.keyring); + const ownKeys = crypto.keyringToKeys({ + value: args.keyring, + encoding: "base64", + }); const sharedSecret = crypto.decapsulate( ownKeys.kemSecretKey, args.kemCiphertext, diff --git a/packages/mtp/package.json b/packages/mtp/package.json index 982593a..e036029 100644 --- a/packages/mtp/package.json +++ b/packages/mtp/package.json @@ -9,7 +9,8 @@ "scripts": { "format": "pnpm exec prettier --write .", "lint": "eslint src --ext .ts,.tsx", - "build": "tsc -p tsconfig.json --noEmit" + "test": "vitest run", + "build": "pnpm run test && tsc -p tsconfig.json --noEmit" }, "dependencies": { "@methanium/ui": "*", diff --git a/packages/mtp/src/context.test.tsx b/packages/mtp/src/context.test.tsx index 7f50aba..b15043a 100644 --- a/packages/mtp/src/context.test.tsx +++ b/packages/mtp/src/context.test.tsx @@ -1,6 +1,62 @@ -import { describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; -import { isPushType, validateResponse } from "./context"; +import { RequestIdAllocator } from "./requestIds"; + +vi.mock("@methanium/ui", () => ({ + toast: { + dismiss: vi.fn(), + error: vi.fn(), + loading: vi.fn(), + }, +})); + +vi.mock("@tensamin/shared/log", () => ({ log: vi.fn() })); +vi.mock("@tensamin/storage/context", () => ({ + useStorage: () => ({ load: vi.fn() }), +})); + +const { completeInitialSynchronization, isPushType, validateResponse } = + await import("./context"); + +const validState = { + SessionId: 7, + VersionNumber: 2, + CacheSchemaVersion: 0, + SyncMode: "full", + Contacts: [], + Communities: [], + Calls: [], + Messages: [], + DeletedMessageIds: [], + DeletedContactIds: [], +}; + +function mockInitialSyncClient( + state: { type: string; data: unknown } = { + type: "ClientStateSync", + data: validState, + }, + acknowledgement: unknown = { type: "ClientStateAck", data: {} }, +) { + const handlers = new Map void>(); + const request = vi.fn().mockResolvedValue(acknowledgement); + const client = { + auth: vi.fn(async () => { + handlers.get(state.type)?.(state as never); + }), + subscribe: vi.fn((type: string, handler: (message: never) => void) => { + handlers.set(type, handler); + return () => handlers.delete(type); + }), + request, + disconnect: vi.fn(), + } as unknown as Parameters[0]; + return { client, handlers, request }; +} + +afterEach(() => { + vi.useRealTimers(); +}); describe("MTP protocol dispatch", () => { it("preserves protocol errors for the request layer", () => { @@ -19,3 +75,146 @@ describe("MTP protocol dispatch", () => { expect(isPushType("UnknownMessage")).toBe(false); }); }); + +describe("browser initial synchronization", () => { + it("validates state, sends a nonzero acknowledgement, then resolves", async () => { + const { client, request } = mockInitialSyncClient(); + + const state = await completeInitialSynchronization( + client, + new RequestIdAllocator(), + new AbortController().signal, + ); + + expect(state.data).toEqual(validState); + expect(request).toHaveBeenCalledWith( + "ClientStateAck", + { SessionId: 7, VersionNumber: 2 }, + { id: 1 }, + ); + }); + + it("does not acknowledge malformed state", async () => { + const { client, request } = mockInitialSyncClient({ + type: "ClientStateSync", + data: { ...validState, SyncMode: "invalid" }, + }); + + await expect( + completeInitialSynchronization( + client, + new RequestIdAllocator(), + new AbortController().signal, + ), + ).rejects.toThrow("Response validation failed"); + expect(request).not.toHaveBeenCalled(); + }); + + it("rejects ErrorNoIota during initial synchronization", async () => { + const { client, request } = mockInitialSyncClient({ + type: "ErrorNoIota", + data: {}, + }); + + await expect( + completeInitialSynchronization( + client, + new RequestIdAllocator(), + new AbortController().signal, + ), + ).rejects.toThrow("No Iota is currently connected"); + expect(request).not.toHaveBeenCalled(); + }); + + it("rejects an acknowledgement protocol error", async () => { + const { client } = mockInitialSyncClient(undefined, { + type: "ErrorInvalidData", + data: {}, + }); + + await expect( + completeInitialSynchronization( + client, + new RequestIdAllocator(), + new AbortController().signal, + ), + ).rejects.toThrow("State acknowledgement failed: ErrorInvalidData"); + }); + + it("times out a missing acknowledgement", async () => { + vi.useFakeTimers(); + const { client } = mockInitialSyncClient(); + vi.mocked(client.request).mockReturnValue(new Promise(() => {})); + const result = completeInitialSynchronization( + client, + new RequestIdAllocator(), + new AbortController().signal, + 100, + 10, + ); + const assertion = expect(result).rejects.toThrow( + "State acknowledgement timed out", + ); + + await vi.advanceTimersByTimeAsync(10); + await assertion; + }); + + it("stops immediately when the connection attempt is cancelled", async () => { + const { client } = mockInitialSyncClient(); + vi.mocked(client.auth).mockImplementation(() => new Promise(() => {})); + const controller = new AbortController(); + const result = completeInitialSynchronization( + client, + new RequestIdAllocator(), + controller.signal, + ); + + controller.abort(new Error("MTP connection lost")); + await expect(result).rejects.toThrow("MTP connection lost"); + }); + + it("times out authentication while waiting for initial state", async () => { + vi.useFakeTimers(); + const { client, handlers } = mockInitialSyncClient(); + vi.mocked(client.auth).mockImplementation(() => { + handlers.get("ClientStateSync")?.({ + type: "ClientStateSync", + data: validState, + } as never); + return new Promise(() => {}); + }); + const result = completeInitialSynchronization( + client, + new RequestIdAllocator(), + new AbortController().signal, + 100, + 10, + ); + const assertion = expect(result).rejects.toThrow( + "MTP authentication timed out", + ); + + await vi.advanceTimersByTimeAsync(100); + await assertion; + }); + + it("uses a fresh request ID namespace for each connection", async () => { + const first = mockInitialSyncClient(); + const second = mockInitialSyncClient(); + + await completeInitialSynchronization( + first.client, + new RequestIdAllocator(), + new AbortController().signal, + ); + await completeInitialSynchronization( + second.client, + new RequestIdAllocator(), + new AbortController().signal, + ); + + expect(first.request.mock.calls[0]?.[2]).toEqual({ id: 1 }); + expect(second.request.mock.calls[0]?.[2]).toEqual({ id: 1 }); + }); +}); diff --git a/packages/mtp/src/context.tsx b/packages/mtp/src/context.tsx index af06ee0..53c1862 100644 --- a/packages/mtp/src/context.tsx +++ b/packages/mtp/src/context.tsx @@ -27,7 +27,20 @@ import { log } from "@tensamin/shared/log"; import { ProtocolError } from "@tensamin/shared/errors"; import { useStorage } from "@tensamin/storage/context"; -import { RECONNECT_RESET, RECONNECT_TRIES, RETRY_INTERVAL } from "./values"; +import { fromWireMessage, toWireData } from "./protocolFields"; +import { RequestIdAllocator } from "./requestIds"; +import { + DISCOVERY_TIMEOUT, + INITIAL_SYNC_TIMEOUT, + RECONNECT_JITTER, + RECONNECT_LONG_INTERVAL, + RECONNECT_RESET, + RECONNECT_TRIES, + RETRY_INTERVAL, + STATE_ACK_TIMEOUT, +} from "./values"; + +type BrowserMtpClient = Awaited>; function base64ToUint8Array(b64: string) { const bin = atob(b64); @@ -51,7 +64,6 @@ export type ProtocolMessage< export type BoundSendFn = ( type: T, data?: z.infer, - options?: { id?: number }, ) => Promise>; export type PushHandler = (message: ProtocolMessage) => void | Promise; @@ -72,6 +84,29 @@ export function isPushType(type: string): boolean { return (PUSH_TYPES as readonly string[]).includes(type); } +function normalizeMtpMessage(message: T): T { + return fromWireMessage(message); +} + +async function requestWithId( + client: BrowserMtpClient, + ids: RequestIdAllocator, + type: string, + data: Record, +) { + let id: number; + try { + id = ids.allocate(); + } catch (error) { + client.disconnect(); + throw error; + } + + return client.request(type, toWireData(data) as Record, { + id, + }); +} + function removeMissingContacts( contacts: Contacts, message: ProtocolMessage, @@ -161,6 +196,120 @@ export function validateResponse( } as ProtocolMessage; } +function abortError(signal: AbortSignal): Error { + return signal.reason instanceof Error + ? signal.reason + : new Error("Initial state synchronization was cancelled"); +} + +function withDeadline( + promise: Promise, + timeoutMs: number, + timeoutMessage: string, + signal: AbortSignal, +): Promise { + return new Promise((resolve, reject) => { + if (signal.aborted) { + reject(abortError(signal)); + return; + } + let settled = false; + const finish = (complete: () => void) => { + if (settled) return; + settled = true; + clearTimeout(timeout); + signal.removeEventListener("abort", onAbort); + complete(); + }; + const timeout = setTimeout( + () => finish(() => reject(new Error(timeoutMessage))), + timeoutMs, + ); + const onAbort = () => finish(() => reject(abortError(signal))); + signal.addEventListener("abort", onAbort, { once: true }); + promise.then( + (value) => finish(() => resolve(value)), + (error: unknown) => finish(() => reject(error)), + ); + }); +} + +export async function completeInitialSynchronization( + client: BrowserMtpClient, + ids: RequestIdAllocator, + signal: AbortSignal, + syncTimeoutMs = INITIAL_SYNC_TIMEOUT, + ackTimeoutMs = STATE_ACK_TIMEOUT, +): Promise> { + const stateSync = new Promise>( + (resolve, reject) => { + let unsubscribeStateSync = () => {}; + let unsubscribeNoIota = () => {}; + const cleanup = () => { + clearTimeout(timeout); + unsubscribeStateSync(); + unsubscribeNoIota(); + signal.removeEventListener("abort", onAbort); + }; + const onAbort = () => { + cleanup(); + reject(abortError(signal)); + }; + const timeout = setTimeout(() => { + cleanup(); + reject(new Error("Initial state synchronization timed out")); + }, syncTimeoutMs); + signal.addEventListener("abort", onAbort, { once: true }); + if (signal.aborted) { + onAbort(); + return; + } + unsubscribeStateSync = client.subscribe("ClientStateSync", (message) => { + cleanup(); + try { + resolve( + validateResponse("ClientStateSync", normalizeMtpMessage(message)), + ); + } catch (error) { + reject(error); + } + }); + unsubscribeNoIota = client.subscribe("ErrorNoIota", () => { + cleanup(); + reject(new Error("No Iota is currently connected")); + }); + }, + ); + const [, state] = await Promise.all([ + withDeadline( + client.auth(), + syncTimeoutMs, + "MTP authentication timed out", + signal, + ), + stateSync, + ]); + if (state.type.startsWith("Error")) { + throw new Error(`State synchronization failed: ${state.type}`); + } + const acknowledgement = normalizeMtpMessage( + await withDeadline( + requestWithId(client, ids, "ClientStateAck", { + SessionId: state.data.SessionId, + VersionNumber: state.data.VersionNumber, + }), + ackTimeoutMs, + "State acknowledgement timed out", + signal, + ), + ); + if (acknowledgement.type.startsWith("Error")) { + throw new Error(`State acknowledgement failed: ${acknowledgement.type}`); + } + if (signal.aborted) throw abortError(signal); + return state; +} + function useMessageHandlers() { const interceptorsRef = useRef(new Set()); const pushHandlersRef = useRef(new Set()); @@ -205,6 +354,7 @@ function BrowserProvider(props: { const clientRef = useRef> | null>( null, ); + const requestIdsRef = useRef(null); const { addInterceptor, interceptorsRef, @@ -223,19 +373,24 @@ function BrowserProvider(props: { // Validation override functions const send: BoundSendFn = useMemo( - () => async (type, data, options) => { + () => async (type, data) => { const client = clientRef.current; + const ids = requestIdsRef.current; if (!client) { throw new Error("mtp is not connected"); } + if (!ids) { + throw new Error("MTP request allocator is unavailable"); + } - const message = await client.request( + const rawMessage = await requestWithId( + client, + ids, type, (data ?? {}) as Record, - options, ); - const response = validateResponse(type, message); + const response = validateResponse(type, normalizeMtpMessage(rawMessage)); setFreshContacts((contacts) => removeMissingContacts(contacts, response)); if (response.type.startsWith("Error")) { const errorData = response.data as Record; @@ -260,7 +415,7 @@ function BrowserProvider(props: { } return client.subscribe(type, (message) => { - handler(validateResponse(type, message)); + handler(validateResponse(type, normalizeMtpMessage(message))); }); }, []); @@ -291,33 +446,39 @@ function BrowserProvider(props: { const scheduleReconnect = (error: unknown) => { if (disposed || reconnectScheduled) return; - if (attempts >= RECONNECT_TRIES) { + attempts += 1; + const shortRetry = attempts <= RECONNECT_TRIES; + if (!shortRetry) { log(0, "mtp", "red", "Reconnection attempts exhausted", error); sonnerToast.error("Connection failed", { id: "mtp-connection-toast", description: error instanceof Error - ? error.message.split(":")[0] - : "Connection lost", + ? `${error.message.split(":")[0]}. Retrying in the background.` + : "Connection lost. Retrying in the background.", icon: null, duration: Infinity, closeButton: true, promise: null, } as unknown as Parameters[1]); - return; + } else { + sonnerToast.loading( + `Reconnecting to server... (attempt ${attempts} of ${RECONNECT_TRIES})`, + { id: "mtp-connection-toast" }, + ); } - attempts += 1; - sonnerToast.loading( - `Reconnecting to server... (attempt ${attempts} of ${RECONNECT_TRIES})`, - { id: "mtp-connection-toast" }, - ); + const baseDelay = shortRetry ? RETRY_INTERVAL : RECONNECT_LONG_INTERVAL; + const jitter = 1 + (Math.random() * 2 - 1) * RECONNECT_JITTER; reconnectScheduled = true; - reconnectTimer = setTimeout(() => { - reconnectScheduled = false; - reconnectTimer = null; - void connect(); - }, RETRY_INTERVAL); + reconnectTimer = setTimeout( + () => { + reconnectScheduled = false; + reconnectTimer = null; + void connect(); + }, + Math.round(baseDelay * jitter), + ); }; async function connect() { @@ -326,10 +487,16 @@ function BrowserProvider(props: { const generation = ++connectionGeneration; let client: Awaited> | null = null; let failed = false; + let connectionReady = false; + const attemptAbort = new AbortController(); const cleanup = () => { + attemptAbort.abort( + new Error("Initial state synchronization was cancelled"), + ); client?.disconnect(); if (clientRef.current === client) { clientRef.current = null; + requestIdsRef.current = null; } clearReconnectResetTimer(); if (generation === connectionGeneration) { @@ -359,19 +526,18 @@ function BrowserProvider(props: { omikronPublicKey = forcedOmikronPublicKey; } else { log(2, "mtp", "purple", "Fetching Omikron data."); - const data = await fetch(`${mtpUrl}api/get/omikron/${userId}`); + const data = await fetch(`${mtpUrl}api/get/omikron/${userId}`, { + signal: AbortSignal.any([ + attemptAbort.signal, + AbortSignal.timeout(DISCOVERY_TIMEOUT), + ]), + }); if (data.status === 404) { - sonnerToast.error("We couldn't reach your Iota", { - description: - "Check your network connection and try restarting your Iota", - icon: null, - duration: Infinity, - closeButton: true, - }); - resolveConnectionRef.current?.(); - cleanup(); - return; + throw new Error("No Omikron assignment is currently available"); + } + if (!data.ok) { + throw new Error(`Omikron discovery failed: HTTP ${data.status}`); } const omikronData = (await data.json()) as { id: number; @@ -404,7 +570,10 @@ function BrowserProvider(props: { clientId: userId, keyring: base64ToUint8Array(keyring), }, - hostPublicKey: omikronPublicKey, + hostPublicKey: { + value: omikronPublicKey, + encoding: "base64", + }, descriptor: "client", pings: true, logger: (event) => { @@ -418,10 +587,12 @@ function BrowserProvider(props: { !failed ) { failed = true; - clientRef.current = null; - setIdentified(false); - setIdentifying(false); - scheduleReconnect(new Error("MTP connection lost")); + const error = new Error("MTP connection lost"); + attemptAbort.abort(error); + if (connectionReady) { + cleanup(); + scheduleReconnect(error); + } } } @@ -456,11 +627,12 @@ function BrowserProvider(props: { const activeClient = client; clientRef.current = activeClient; + requestIdsRef.current = new RequestIdAllocator(); for (const type of PUSH_TYPES) { activeClient.subscribe(type, (message) => { let validated: ProtocolMessage; try { - validated = validateResponse(type, message); + validated = validateResponse(type, normalizeMtpMessage(message)); } catch (error) { log(1, "mtp", "red", "Failed to validate push message", error, { type, @@ -482,80 +654,45 @@ function BrowserProvider(props: { if (validated.type === "GetStates") { lastInitialStateRef.current = validated; } + if ( + validated.type === "ErrorNoIota" && + clientRef.current === activeClient && + !failed + ) { + failed = true; + const error = new Error("No Iota is currently connected"); + attemptAbort.abort(error); + cleanup(); + scheduleReconnect(error); + } }); } - setReadyState(activeClient.state); - - clearReconnectTimer(); - - // Schedule reconnect reset - clearReconnectResetTimer(); - reconnectResetTimer = setTimeout(() => { - attempts = 0; - reconnectResetTimer = null; - }, RECONNECT_RESET * 1_000); - setReadyState(activeClient.state); setIdentifying(true); - const stateSync = new Promise>( - (resolve, reject) => { - let unsubscribeStateSync = () => {}; - let unsubscribeNoIota = () => {}; - const cleanupStateSync = () => { - clearTimeout(timeout); - unsubscribeStateSync(); - unsubscribeNoIota(); - }; - const timeout = setTimeout(() => { - cleanupStateSync(); - reject(new Error("Initial state synchronization timed out")); - }, 120_000); - unsubscribeStateSync = activeClient.subscribe( - "ClientStateSync", - (message) => { - cleanupStateSync(); - try { - resolve(validateResponse("ClientStateSync", message)); - } catch (error) { - reject(error); - } - }, - ); - unsubscribeNoIota = activeClient.subscribe("ErrorNoIota", () => { - cleanupStateSync(); - reject(new Error("No Iota is currently connected")); - }); - }, + const ids = requestIdsRef.current; + if (!ids) throw new Error("MTP request allocator is unavailable"); + const finalResponse = await completeInitialSynchronization( + activeClient, + ids, + attemptAbort.signal, ); - const [, finalResponse] = await Promise.all([ - activeClient.auth(), - stateSync, - ]); - - if (finalResponse.type.startsWith("Error")) { - throw new Error( - `State synchronization failed: ${finalResponse.type}`, - ); - } - - const acknowledgement = await activeClient.request("ClientStateAck", { - SessionId: finalResponse.data.SessionId, - VersionNumber: finalResponse.data.VersionNumber, - }); - if (acknowledgement.type.startsWith("Error")) { - throw new Error( - `State acknowledgement failed: ${acknowledgement.type}`, - ); - } if (disposed || clientRef.current !== activeClient) return; setFreshContacts(finalResponse.data.Contacts); setFreshCommunities(finalResponse.data.Communities); setFreshCalls(finalResponse.data.Calls); + connectionReady = true; setIdentifying(false); setIdentified(true); + + clearReconnectTimer(); + clearReconnectResetTimer(); + reconnectResetTimer = setTimeout(() => { + attempts = 0; + reconnectResetTimer = null; + }, RECONNECT_RESET * 1_000); resolveConnectionRef.current?.(); } catch (connectError) { if (disposed || generation !== connectionGeneration) { @@ -589,6 +726,7 @@ function BrowserProvider(props: { clientRef.current?.disconnect(); clientRef.current = null; + requestIdsRef.current = null; setReadyState(ConnectionState.Disconnected); setIdentified(false); setIdentifying(false); @@ -650,9 +788,9 @@ function BrowserProvider(props: { }, [connected, identified, mtpUrl, send, subscribe, subscribePush, mtpRef]); const sendQueued: BoundSendFn = useMemo( - () => async (type, data, options) => { + () => async (type, data) => { const mtp = await mtpRef.get(); - const response = await mtp.send(type, data, options); + const response = await mtp.send(type, data); for (const interceptor of interceptorsRef.current) { void Promise.resolve( interceptor({ type, data, response: response as ProtocolMessage }), @@ -724,16 +862,32 @@ function TauriProvider(props: { if (next.error) { log(0, "android", "orange", "MTP connection failed", next.error); } - setSnapshot(next); - if (!next.identified || next.state === undefined) return; + if (!next.identified) { + setSnapshot(next); + return; + } + if (next.state === undefined) { + setSnapshot({ + ...next, + identified: false, + error: "Native MTP connection omitted initial state", + }); + return; + } const parsed = schemas.ClientStateSync.response.safeParse(next.state); if (!parsed.success) { log(0, "mtp", "red", "Invalid native MTP state", parsed.error); + setSnapshot({ + ...next, + identified: false, + error: "Invalid ClientStateSync payload", + }); return; } setFreshContacts(parsed.data.Contacts); setFreshCommunities(parsed.data.Communities); setFreshCalls(parsed.data.Calls); + setSnapshot(next); }, []); const dispatchMessage = useCallback( @@ -744,7 +898,7 @@ function TauriProvider(props: { try { validated = validateResponse( message.type as keyof Schemas & string, - message, + normalizeMtpMessage(message), ); } catch (error) { log(1, "mtp", "red", "Failed to validate native MTP message", error); @@ -846,13 +1000,12 @@ function TauriProvider(props: { }, [props.blockConnection]); const send = useCallback( - async (type, data, options) => { + async (type, data) => { const response = await invoke("mtp_request", { typeName: type, data: data ?? {}, - id: options?.id, }); - const validated = validateResponse(type, response); + const validated = validateResponse(type, normalizeMtpMessage(response)); setFreshContacts((contacts) => removeMissingContacts(contacts, validated), ); diff --git a/packages/mtp/src/index.ts b/packages/mtp/src/index.ts index 39bce46..19f5acd 100644 --- a/packages/mtp/src/index.ts +++ b/packages/mtp/src/index.ts @@ -1,4 +1,5 @@ export { Provider, useMTP } from "./context"; +export { RequestIdAllocator } from "./requestIds"; export type { BoundSendFn, MTPExchange, diff --git a/packages/mtp/src/protocolFields.test.ts b/packages/mtp/src/protocolFields.test.ts new file mode 100644 index 0000000..ef0c18f --- /dev/null +++ b/packages/mtp/src/protocolFields.test.ts @@ -0,0 +1,44 @@ +import { describe, expect, it } from "vitest"; + +import { fromWireData, toWireData } from "./protocolFields"; + +describe("MTP protocol field translation", () => { + it("maps application message fields to MTP wire fields", () => { + expect( + toWireData({ + Messages: [{ Content: "abc", MessageId: 4 }], + }), + ).toEqual({ + Messages: [{ AppContent: "abc", AppMessageId: 4 }], + }); + }); + + it("maps MTP wire fields back to application fields", () => { + expect( + fromWireData({ + AppCreatedAt: 123, + Message: { AppContent: "abc", AppMessageId: 4 }, + }), + ).toEqual({ + CreatedAt: 123, + Message: { Content: "abc", MessageId: 4 }, + }); + }); + + it("preserves byte arrays and unrelated fields", () => { + const bytes = new Uint8Array([1, 2, 3]); + const translated = toWireData({ Payload: bytes, Other: "value" }) as { + Payload: Uint8Array; + Other: string; + }; + + expect(translated.Payload).toBe(bytes); + expect(translated.Other).toBe("value"); + }); + + it("rejects field mapping collisions", () => { + expect(() => toWireData({ Content: "a", AppContent: "b" })).toThrow( + "MTP field translation collision", + ); + }); +}); diff --git a/packages/mtp/src/protocolFields.ts b/packages/mtp/src/protocolFields.ts new file mode 100644 index 0000000..3ec3d5d --- /dev/null +++ b/packages/mtp/src/protocolFields.ts @@ -0,0 +1,58 @@ +const APPLICATION_TO_WIRE_FIELDS = { + Content: "AppContent", + CreatedAt: "AppCreatedAt", + MessageId: "AppMessageId", +} as const; + +const WIRE_TO_APPLICATION_FIELDS = { + AppContent: "Content", + AppCreatedAt: "CreatedAt", + AppMessageId: "MessageId", +} as const; + +function mapProtocolFields( + value: unknown, + fieldMap: Readonly>, +): unknown { + if ( + value === null || + typeof value !== "object" || + value instanceof Uint8Array + ) { + return value; + } + + if (Array.isArray(value)) { + return value.map((item) => mapProtocolFields(item, fieldMap)); + } + + const source = value as Record; + const target: Record = {}; + + for (const [key, child] of Object.entries(source)) { + const mappedKey = fieldMap[key] ?? key; + + if (mappedKey in target) { + throw new Error(`MTP field translation collision for ${mappedKey}`); + } + + target[mappedKey] = mapProtocolFields(child, fieldMap); + } + + return target; +} + +export function toWireData(value: unknown): unknown { + return mapProtocolFields(value, APPLICATION_TO_WIRE_FIELDS); +} + +export function fromWireData(value: unknown): unknown { + return mapProtocolFields(value, WIRE_TO_APPLICATION_FIELDS); +} + +export function fromWireMessage(message: T): T { + return { + ...message, + data: fromWireData(message.data), + }; +} diff --git a/packages/mtp/src/requestIds.test.ts b/packages/mtp/src/requestIds.test.ts new file mode 100644 index 0000000..82fd508 --- /dev/null +++ b/packages/mtp/src/requestIds.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from "vitest"; + +import { RequestIdAllocator } from "./requestIds"; + +describe("MTP request ID allocation", () => { + it("allocates nonzero request IDs monotonically", () => { + const ids = new RequestIdAllocator(); + + expect(ids.allocate()).toBe(1); + expect(ids.allocate()).toBe(2); + expect(new RequestIdAllocator().allocate()).toBe(1); + }); + + it("does not wrap exhausted request IDs", () => { + const ids = new RequestIdAllocator(0x1_0000_0000); + + expect(() => ids.allocate()).toThrow("MTP request ID space exhausted"); + }); + + it("rejects invalid allocator states", () => { + expect(() => new RequestIdAllocator(0)).toThrow( + "invalid MTP request ID allocator state", + ); + }); +}); diff --git a/packages/mtp/src/requestIds.ts b/packages/mtp/src/requestIds.ts new file mode 100644 index 0000000..5581e8a --- /dev/null +++ b/packages/mtp/src/requestIds.ts @@ -0,0 +1,24 @@ +const MAX_MTP_REQUEST_ID = 0xffff_ffff; + +export class RequestIdAllocator { + #next: number; + + constructor(next = 1) { + if ( + !Number.isSafeInteger(next) || + next <= 0 || + next > MAX_MTP_REQUEST_ID + 1 + ) { + throw new RangeError("invalid MTP request ID allocator state"); + } + this.#next = next; + } + + allocate(): number { + if (this.#next > MAX_MTP_REQUEST_ID) { + throw new Error("MTP request ID space exhausted for this connection"); + } + + return this.#next++; + } +} diff --git a/packages/mtp/src/values.ts b/packages/mtp/src/values.ts index d9f6cd4..c5ba321 100644 --- a/packages/mtp/src/values.ts +++ b/packages/mtp/src/values.ts @@ -1,3 +1,8 @@ export const RETRY_INTERVAL = 3_000; export const RECONNECT_TRIES = 3; export const RECONNECT_RESET = 6; +export const RECONNECT_LONG_INTERVAL = 60_000; +export const RECONNECT_JITTER = 0.2; +export const DISCOVERY_TIMEOUT = 20_000; +export const INITIAL_SYNC_TIMEOUT = 120_000; +export const STATE_ACK_TIMEOUT = 30_000; diff --git a/packages/notifications/src/context.tsx b/packages/notifications/src/context.tsx index 1835dc1..7a8b32a 100644 --- a/packages/notifications/src/context.tsx +++ b/packages/notifications/src/context.tsx @@ -87,15 +87,9 @@ export default function Provider(props: { children: React.ReactNode }) { moveUserIdToTop(data.SenderId); if (await load("settings.receive_confirmations")) { - void send( - "MessageState", - { - MessageState: "received", - }, - { - id: data.Message.SendTime, - }, - ); + void send("MessageState", { + MessageState: "received", + }); } } diff --git a/packages/settings/src/layout.tsx b/packages/settings/src/layout.tsx index 53759cd..5d49f0b 100644 --- a/packages/settings/src/layout.tsx +++ b/packages/settings/src/layout.tsx @@ -1,8 +1,8 @@ -import { Outlet, useLocation, useNavigate } from "@tanstack/react-router"; -import { Button, ClearStorageButton, cn, useIsMobile } from "@methanium/ui"; +import { Outlet, useLocation } from "@tanstack/react-router"; +import { Button, useIsMobile } from "@methanium/ui"; import { ArrowLeft } from "lucide-react"; -import { settingsNavigation } from "./manifest"; +import { SettingsSidebar } from "./sidebar"; export default function SettingsLayout() { const isMobile = useIsMobile(); @@ -36,47 +36,3 @@ export default function SettingsLayout() {
    ); } - -export function SettingsSidebar({ - mobile = false, - className, -}: { - mobile?: boolean; - className?: string; -}) { - const navigate = useNavigate(); - const categories = [ - ...new Set(settingsNavigation.map((page) => page.category)), - ]; - - return ( -
    - {categories.map((category) => ( -
    -

    {category}

    - {settingsNavigation - .filter((page) => page.category === category) - .map((page) => ( - - ))} -
    - ))} -
    - -
    -
    - ); -} diff --git a/packages/settings/src/manifest.ts b/packages/settings/src/manifest.ts index 41fe14a..1afdd5a 100644 --- a/packages/settings/src/manifest.ts +++ b/packages/settings/src/manifest.ts @@ -8,46 +8,24 @@ import Profile from "./pages/profile"; import Security from "./pages/security"; import Theme from "./pages/theme"; import Hotkeys from "./pages/hotkeys"; +import { settingsNavigation } from "./navigation"; + +const pageComponents = { + profile: Profile, + security: Security, + chat: Chat, + call: Call, + cache: Cache, + theme: Theme, + accessibility: Accessibility, + hotkeys: Hotkeys, + licenses: Licenses, +} as const; export const settingsPages = [ { path: "/", component: Index }, - { - category: "account", - path: "profile", - label: "Profile", - component: Profile, - }, - { - category: "account", - path: "security", - label: "Security", - component: Security, - }, - { category: "general", path: "chat", label: "Chat", component: Chat }, - { category: "general", path: "call", label: "Call", component: Call }, - { category: "application", path: "cache", label: "Cache", component: Cache }, - { category: "application", path: "theme", label: "Theme", component: Theme }, - { - category: "application", - path: "accessibility", - label: "Accessibility", - component: Accessibility, - }, - { - category: "application", - path: "hotkeys", - label: "Hotkeys", - component: Hotkeys, - }, - { - category: "application", - path: "licenses", - label: "Licenses", - component: Licenses, - }, + ...settingsNavigation.map((page) => ({ + ...page, + component: pageComponents[page.path], + })), ] as const; - -export const settingsNavigation = settingsPages.filter( - (page): page is Exclude<(typeof settingsPages)[number], { path: "/" }> => - page.path !== "/", -); diff --git a/packages/settings/src/navigation.ts b/packages/settings/src/navigation.ts new file mode 100644 index 0000000..b47fae9 --- /dev/null +++ b/packages/settings/src/navigation.ts @@ -0,0 +1,31 @@ +export const settingsNavigation = [ + { + category: "account", + path: "profile", + label: "Profile", + }, + { + category: "account", + path: "security", + label: "Security", + }, + { category: "general", path: "chat", label: "Chat" }, + { category: "general", path: "call", label: "Call" }, + { category: "application", path: "cache", label: "Cache" }, + { category: "application", path: "theme", label: "Theme" }, + { + category: "application", + path: "accessibility", + label: "Accessibility", + }, + { + category: "application", + path: "hotkeys", + label: "Hotkeys", + }, + { + category: "application", + path: "licenses", + label: "Licenses", + }, +] as const; diff --git a/packages/settings/src/pages/index.tsx b/packages/settings/src/pages/index.tsx index 803a0c1..b5d04e3 100644 --- a/packages/settings/src/pages/index.tsx +++ b/packages/settings/src/pages/index.tsx @@ -1,4 +1,4 @@ -import { SettingsSidebar } from "../layout"; +import { SettingsSidebar } from "../sidebar"; export default function Page() { return ( diff --git a/packages/settings/src/sidebar.tsx b/packages/settings/src/sidebar.tsx new file mode 100644 index 0000000..3a2155e --- /dev/null +++ b/packages/settings/src/sidebar.tsx @@ -0,0 +1,48 @@ +import { Button, ClearStorageButton, cn } from "@methanium/ui"; +import { useNavigate } from "@tanstack/react-router"; + +import { settingsNavigation } from "./navigation"; + +export function SettingsSidebar({ + mobile = false, + className, +}: { + mobile?: boolean; + className?: string; +}) { + const navigate = useNavigate(); + const categories = [ + ...new Set(settingsNavigation.map((page) => page.category)), + ]; + + return ( +
    + {categories.map((category) => ( +
    +

    {category}

    + {settingsNavigation + .filter((page) => page.category === category) + .map((page) => ( + + ))} +
    + ))} +
    + +
    +
    + ); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index faff301..0cbdd6e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: overrides: '@methanium/ui': https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - mtp: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz + mtp: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz importers: @@ -16,17 +16,17 @@ importers: specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) mtp: - specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz - version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz sonner: - specifier: ^2.0.7 - version: 2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^2.0.8 + version: 2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) devDependencies: '@eslint/js': specifier: ^10.0.1 version: 10.0.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) '@types/node': - specifier: ^26.1.2 + specifier: ^26.2.0 version: 26.2.0 '@types/react': specifier: ^19.2.18 @@ -35,20 +35,20 @@ importers: specifier: ^19.2.4 version: 19.2.4(@types/react@19.2.18) '@typescript-eslint/parser': - specifier: ^8.66.0 - version: 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + specifier: ^8.67.0 + version: 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) eslint: - specifier: ^10.8.0 + specifier: ^10.8.1 version: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) eslint-plugin-react-hooks: specifier: ^7.1.1 version: 7.1.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0) fallow: - specifier: ^3.14.0 - version: 3.14.0 + specifier: ^3.17.0 + version: 3.17.0 globals: - specifier: ^17.9.0 - version: 17.9.0 + specifier: ^17.11.0 + version: 17.11.0 prettier: specifier: ^3.9.6 version: 3.9.6 @@ -56,11 +56,11 @@ importers: specifier: ^6.0.3 version: 6.0.3 typescript-eslint: - specifier: ^8.66.0 - version: 8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + specifier: ^8.67.0 + version: 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) vitest: - specifier: ^4.1.10 - version: 4.1.10(@types/node@26.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0)) + specifier: ^4.1.11 + version: 4.1.11(@types/node@26.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0)) apps/electron: devDependencies: @@ -98,8 +98,8 @@ importers: specifier: workspace:* version: link:../../packages/storage mtp: - specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz - version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz react: specifier: ^19.2.8 version: 19.2.8 @@ -289,6 +289,9 @@ importers: globals: specifier: ^17.9.0 version: 17.9.0 + mtp: + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz typescript: specifier: ~6.0.3 version: 6.0.3 @@ -352,6 +355,9 @@ importers: lucide-react: specifier: ^1.29.0 version: 1.30.0(react@19.2.8) + mtp: + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz react: specifier: ^19.2.8 version: 19.2.8 @@ -424,6 +430,9 @@ importers: packages/crypto: dependencies: + mtp: + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz react: specifier: ^19.2.8 version: 19.2.8 @@ -468,8 +477,8 @@ importers: specifier: workspace:* version: link:../storage mtp: - specifier: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz - version: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz react: specifier: ^19.2.8 version: 19.2.8 @@ -1264,8 +1273,8 @@ packages: '@codemirror/autocomplete@6.20.3': resolution: {integrity: sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==} - '@codemirror/commands@6.10.4': - resolution: {integrity: sha512-Ryk9y9T0FFVF0cUGhAknveAyUOl/A1qReTFi+qPKtOh2Z9F4AUBz3XOrYD4ZEgZirdugVzHvd/2/Wcwy5OliTg==} + '@codemirror/commands@6.11.0': + resolution: {integrity: sha512-/K4Rl5BN0OtTiPWmJCdqODu38XnDMsDxKY5rgrPnCkutPTJf2wVbkoixLfealF5Kwse/s8P8M5jAiURiwSwnFA==} '@codemirror/lang-css@6.3.1': resolution: {integrity: sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==} @@ -1288,8 +1297,8 @@ packages: '@codemirror/state@6.7.1': resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==} - '@codemirror/view@6.43.8': - resolution: {integrity: sha512-qtItTDssZ/5GFfi94hrILu9j/VUeFPDPkhovEfmWFj2ipTxnzPB8DdHgfbb8HYTzLTYhrndKmyQxXUz/PDLenw==} + '@codemirror/view@6.43.9': + resolution: {integrity: sha512-sTuUzTpPMFebRhg6dawChoKKgndIwfjmJgKVxBefPElcU2NwQ6AFroupk0SFqEerQyZOGRfDNnSN8Dw/lMAsXw==} '@dotenvx/dotenvx@1.75.1': resolution: {integrity: sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ==} @@ -1537,43 +1546,43 @@ packages: resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@fallow-cli/darwin-arm64@3.14.0': - resolution: {integrity: sha512-seaix3OqADcq90PkPOOPrN8Jl7QZDGjFziHA85Ikp+lGSHVjJ2IMyGh/QKLhvi9Q6Ha3Y//F0+PFFGNd0Gi4mw==} + '@fallow-cli/darwin-arm64@3.17.0': + resolution: {integrity: sha512-u9O4aQaTSdaZaa4MAVEZEiwOx6QQzChymyQPrxV6KvDcVbcl0oYSekJKdvN4gEqUY8ClMze9gWS1tbn/W3N4dQ==} cpu: [arm64] os: [darwin] - '@fallow-cli/darwin-x64@3.14.0': - resolution: {integrity: sha512-qgYZHHTFobuJCtON7aVe/tXCUjiF/9nKT4tNLVfUPH4Qe9KwieO4rAuknDOnxkjzsWPO4MfHyCbcVdslf4JMnw==} + '@fallow-cli/darwin-x64@3.17.0': + resolution: {integrity: sha512-l3tZJovnCa8j+im4qTl4GVSfrx4gisJYeHDwb5TbcdTGaWYz42gHriAaz5MhOR8S24q3xRegX8QrI8PA4XXU4g==} cpu: [x64] os: [darwin] - '@fallow-cli/linux-arm64-gnu@3.14.0': - resolution: {integrity: sha512-FwmIG391lMViBXh1cAvOcwQxbI2sLjEYkugFauVbmntjuJt6xVxQXAxjybdFXSL/jjfFnbAzPKy9oHlhq3sA6A==} + '@fallow-cli/linux-arm64-gnu@3.17.0': + resolution: {integrity: sha512-IAjS6qR4tHcRo1y5lzYT6mktN/ATPyPNrJ6yjwTORwwQV1YfMO58A5zGBfJlPBY+lUmaMZ9w37ftvH9a2AS4dQ==} cpu: [arm64] os: [linux] - '@fallow-cli/linux-arm64-musl@3.14.0': - resolution: {integrity: sha512-x4R9aNT2kIoSHRIZ5s2MZ+swyb3uutV6SSYCwWhPSE5UI/oCEYWNWiYS7uKMLM0cTuMPVcsm2qMTd4iYA3ACLw==} + '@fallow-cli/linux-arm64-musl@3.17.0': + resolution: {integrity: sha512-Oe1dvk5Wt5Bmnxfc6HufJTaFY9SEwDVrZpnSdVQlv+nvz7DzrTK1r91cR3Ip477ANSLa9XD/MHPMpfqqo0dlZg==} cpu: [arm64] os: [linux] - '@fallow-cli/linux-x64-gnu@3.14.0': - resolution: {integrity: sha512-8kBxy9FkwKjiH1C19T0nSkmbtldwVyWLQWajIqvyHE0x4rurHhve7RQrwEDPzNMFu7OgYCMU1nXr/AMIJ6Kg9w==} + '@fallow-cli/linux-x64-gnu@3.17.0': + resolution: {integrity: sha512-XgLU2a51zuky7gifjVDHuiJGToAReDsVCDcyDF84TQz/h3bqO0iRkpDL8dh7+HODku84+EffpK5ZHY19n6Ij0w==} cpu: [x64] os: [linux] - '@fallow-cli/linux-x64-musl@3.14.0': - resolution: {integrity: sha512-9TAdXSpYvk9WkKy2GR8T/PHbq7QCTO/SYUmiZ+EAJUMzXBvSfnpj8cCGQpeAD000Nb+o7rL94lIAPJMAqMKO3Q==} + '@fallow-cli/linux-x64-musl@3.17.0': + resolution: {integrity: sha512-GnDZx2kbLKKdYAp05NSKv6CZHgzEKvhRd0btCKFMMpUEhdzmr4uh2Qb4UzKDBg/q2r1EhkzN4b/qC+tbFCmtwA==} cpu: [x64] os: [linux] - '@fallow-cli/win32-arm64-msvc@3.14.0': - resolution: {integrity: sha512-xc495cracyJL+0UKwcqNhofIz2K5XiJbb+YFhxrbSrrbm+EVDnQKpCOzzOJYbm7RPxF6XOxJpATn7ciBy7Rqrw==} + '@fallow-cli/win32-arm64-msvc@3.17.0': + resolution: {integrity: sha512-u9n5WzPuKuC1PKegKQknWtngAUJ2szQaRXsbY54s7UMqeFNyC+W04LV5D+sEZywU7L0kzL+Kck9LxFLXBQcgvA==} cpu: [arm64] os: [win32] - '@fallow-cli/win32-x64-msvc@3.14.0': - resolution: {integrity: sha512-ihyCZ5GMoYGnzlPP6b5pZBBcGZhDHDW2u1YEGkZEuf3pbW6E45U7Hhf213cE2CCheScXOirK6AKWnLM/Qj4c2A==} + '@fallow-cli/win32-x64-msvc@3.17.0': + resolution: {integrity: sha512-/OcyxHuCKabzQ9hKIjM/CFJ9fr30n0Mw5MK6nzi5rn26mbYUgh073UZq4FONOpPJ/FqHtC726rxpgBtR4qS+gg==} cpu: [x64] os: [win32] @@ -1598,8 +1607,8 @@ packages: '@fontsource-variable/public-sans@5.3.0': resolution: {integrity: sha512-AVfkmAt50BMXWpOO21FAntiJFKGX6xTc2dSL8dxtDteONe9IuRXJWGbs0EbG955vAMCq23ENeuopuW87cGWDSQ==} - '@hono/node-server@2.1.0': - resolution: {integrity: sha512-XovyyCCnBzW+zKu+z/zq8hwNs4KOR5rEMAOxo2f40Q5xoOI37IMm6MIg2COOUtUApo0i6850MTBKH2u4QLGIqg==} + '@hono/node-server@2.1.1': + resolution: {integrity: sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==} engines: {node: '>=20'} peerDependencies: hono: ^4 @@ -2226,32 +2235,32 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@shikijs/core@4.4.2': - resolution: {integrity: sha512-StyzbAyxg2/tBGf78gwbBkGyeQ73lf8UiJArFaQhTQIDqQOCKPCQFanvrs4/Yv3Yfyc+ONInJM6K+FMIf+P+kA==} + '@shikijs/core@4.4.3': + resolution: {integrity: sha512-QCR4q2ZO/ILJEuwiBMel4wdcTDb1JGwfjKTxPDF6x8ixOaluPrVqIn06C99AcRPhmYlBR56d/Fb+GN58GzExpg==} engines: {node: '>=20'} - '@shikijs/engine-javascript@4.4.2': - resolution: {integrity: sha512-MnIkeqWdVPUWsxlx8gKLVCJFTsqrQJgpTPBPpQwaFeJ56lOnJxj5aN2LUFnfxUEcvOQuNocmbaMnVrCEln6rkw==} + '@shikijs/engine-javascript@4.4.3': + resolution: {integrity: sha512-FbOjFJp9VLdo1Wevs10BBtVxiTWwNLqZh5Gkhjgda/ioL15YOgeSl9n+6XMa3qRlPQzfhFNe641SrynFHYG0nQ==} engines: {node: '>=20'} - '@shikijs/engine-oniguruma@4.4.2': - resolution: {integrity: sha512-GLhowz1+jixjz+wiZ3wMnOn1jTxiFCGl2PkXufivbnwPHKuyw1AYqu5/hbWhZZ2oAb0NP05WUJhYeigY14drnw==} + '@shikijs/engine-oniguruma@4.4.3': + resolution: {integrity: sha512-EcOQkxdxGQrc1Row/cC2c96/v1dbZqGnEVu1qTuT/MJmp6+cXCvQussowVmCv5Tqr3KuY3c7IbM6HTW3LJ1k9w==} engines: {node: '>=20'} - '@shikijs/langs@4.4.2': - resolution: {integrity: sha512-8DfeusD+Zdv/eYIDdXyJTUnSMHt+aAWjAOCXV20HNGAHRlInXpG8wh421v6B91WOm9TFwRLN+b/LG5F2NAIojg==} + '@shikijs/langs@4.4.3': + resolution: {integrity: sha512-ePic0yfAJGOF83D5wBHK/00EjK65oahBYxFk5epgq33WRv7X9UuxLEV8PtR0szC0z8dl7INIpIodB99JRFlR+A==} engines: {node: '>=20'} - '@shikijs/primitive@4.4.2': - resolution: {integrity: sha512-l6fQQKsOMlz72n38fztmSgZ76MO6KSWuw8o+GJ+FhmqrpC9pIOJNQNXGgbb5yX2AwpzlEHwsaLPnk/8o4Fm+rA==} + '@shikijs/primitive@4.4.3': + resolution: {integrity: sha512-m0wBeLDQDeIxRdUmrCPdQqfuUamDwRL5isCfYbguKD6NiaKpVbsv+3J81DyIKgNW5h4WAIIr8T4EkgQrBBxvaQ==} engines: {node: '>=20'} - '@shikijs/themes@4.4.2': - resolution: {integrity: sha512-H0CFoL07ddDC2Dd6EdrPYNkRhUR6YCkJlnuYFceYYUJJA5TIm2b5B33qqiDYryBExgbKMndFJPb2u1gTuqO37g==} + '@shikijs/themes@4.4.3': + resolution: {integrity: sha512-w8UHjeUnIR965KMWJHUPXOc2mNJUnK3vpVLYLvw5IYU2mnTTJ89E24OrJDBNiJDQ0qzb0tc4l7mrIXx5cFeIyw==} engines: {node: '>=20'} - '@shikijs/types@4.4.2': - resolution: {integrity: sha512-PFYitV4vpDr/iPCIhnHp+Q4ftic5N5VeNJ3KQ1O8gn3h2ar8qgwMAXF7tq4m1CWaMS60fV4VqF6vfnWH4F7vqQ==} + '@shikijs/types@4.4.3': + resolution: {integrity: sha512-UEJxmRR++MAGR6hugn0vgVS2W/6lWAts84FFSrnlH9sP0LNol7E5+NQ792pH8liWUhyMyjhTgSUH3k7iD7tc5g==} engines: {node: '>=20'} '@shikijs/vscode-textmate@10.0.2': @@ -2652,6 +2661,14 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/eslint-plugin@8.67.0': + resolution: {integrity: sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.67.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/parser@8.66.0': resolution: {integrity: sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2659,22 +2676,45 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/parser@8.67.0': + resolution: {integrity: sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/project-service@8.66.0': resolution: {integrity: sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/project-service@8.67.0': + resolution: {integrity: sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/scope-manager@8.66.0': resolution: {integrity: sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.67.0': + resolution: {integrity: sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/tsconfig-utils@8.66.0': resolution: {integrity: sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/tsconfig-utils@8.67.0': + resolution: {integrity: sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/type-utils@8.66.0': resolution: {integrity: sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2682,16 +2722,33 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/type-utils@8.67.0': + resolution: {integrity: sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/types@8.66.0': resolution: {integrity: sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.67.0': + resolution: {integrity: sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.66.0': resolution: {integrity: sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/typescript-estree@8.67.0': + resolution: {integrity: sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/utils@8.66.0': resolution: {integrity: sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2699,10 +2756,21 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/utils@8.67.0': + resolution: {integrity: sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/visitor-keys@8.66.0': resolution: {integrity: sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.67.0': + resolution: {integrity: sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript/typescript-aix-ppc64@7.0.2': resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} engines: {node: '>=16.20.0'} @@ -2839,11 +2907,11 @@ packages: babel-plugin-react-compiler: optional: true - '@vitest/expect@4.1.10': - resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} + '@vitest/expect@4.1.11': + resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} - '@vitest/mocker@4.1.10': - resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} + '@vitest/mocker@4.1.11': + resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2853,20 +2921,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.10': - resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} + '@vitest/pretty-format@4.1.11': + resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} - '@vitest/runner@4.1.10': - resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} + '@vitest/runner@4.1.11': + resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} - '@vitest/snapshot@4.1.10': - resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} + '@vitest/snapshot@4.1.11': + resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} - '@vitest/spy@4.1.10': - resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} + '@vitest/spy@4.1.11': + resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} - '@vitest/utils@4.1.10': - resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} + '@vitest/utils@4.1.11': + resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} @@ -2925,8 +2993,8 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + ansi-regex@6.3.0: + resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==} engines: {node: '>=12'} ansi-styles@4.3.0: @@ -3024,8 +3092,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.11.12: - resolution: {integrity: sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==} + baseline-browser-mapping@2.11.15: + resolution: {integrity: sha512-FwMjJJ7HnyZpWe+oWxegG0fezZyBZUagI5LZEoO3GCbtbKNwRfMH9Ue5d5v01PNePBy1QSfPSDTTeVL0Hb9EzA==} engines: {node: '>=6.0.0'} hasBin: true @@ -3054,8 +3122,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.28.7: - resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==} + browserslist@4.28.8: + resolution: {integrity: sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -3242,8 +3310,8 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - content-type@2.0.0: - resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + content-type@2.1.0: + resolution: {integrity: sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==} engines: {node: '>=18'} convert-source-map@2.0.0: @@ -3406,8 +3474,8 @@ packages: resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} engines: {node: '>=18'} - default-browser@5.5.0: - resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + default-browser@5.5.1: + resolution: {integrity: sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==} engines: {node: '>=18'} defer-to-connect@2.0.1: @@ -3507,8 +3575,8 @@ packages: electron-publish@26.15.3: resolution: {integrity: sha512-g/2bn8YTavY4cuS5F+jOS7zmZbXXBV8KZ8yHKfJjFPoKtzBqrpCdNPxBd3tqdBwP7BVd0lGzf7Bk2s0KesWZ4Q==} - electron-to-chromium@1.5.402: - resolution: {integrity: sha512-/oOpMaPT6Yg+6/1XQhyIPlzgj7Ye9zf+nNM2Uh6OcE2G2oNptWazFa+qB2Pdqqbsc9KnIDzgAntoYN0dbwOXwA==} + electron-to-chromium@1.5.411: + resolution: {integrity: sha512-gglkxzokjHfawpGxq75XdBV2/l3BAPzrsMs70qgaZdTW5rpV1tC4MdgJVP9fN126bODA4ZJQkn1wryEzJyQXIg==} electron-winstaller@5.4.0: resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} @@ -3596,8 +3664,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@2.3.1: - resolution: {integrity: sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==} + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} es-object-atoms@1.1.2: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} @@ -3714,8 +3782,8 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - eventsource-parser@3.1.0: - resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} + eventsource-parser@3.1.1: + resolution: {integrity: sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==} engines: {node: '>=18.0.0'} eventsource@3.0.7: @@ -3750,13 +3818,13 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - fallow-type-aware@3.14.0: - resolution: {integrity: sha512-D8+bNELjmoVV2dKpmHplQ1YzuheHltmZKaOVJ//hx7h8vFNyp5H3hcJV8rR26ofBU51z9K5eyA7FpgP3hebjwg==} + fallow-type-aware@3.17.0: + resolution: {integrity: sha512-DFtZUK5oqP56tSsrBWPzjrTIwPPxwlBV8QoSaGghMru347Nqj8ZBY6u9HFa/TIPcxvFU/zIZMRF8xS/XAWQTzg==} engines: {node: '>=20'} hasBin: true - fallow@3.14.0: - resolution: {integrity: sha512-hse+sChmWkrffLiZDPGdNSyiLybVEhgoiYCIYgqLwdYhfTCO+f2PS1g+gMhGAJdLlYpZ75tFwRoMBFmZjN3Q6g==} + fallow@3.17.0: + resolution: {integrity: sha512-tbLuvsPq3I2CzpoF/9MgSQ7hWzOqlj3avFUAmCr1J9OERE6z714SlDmA38NVvNy/zuK/70utXB3/b33xC9z29g==} engines: {node: '>=22'} hasBin: true @@ -3974,6 +4042,10 @@ packages: resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} engines: {node: '>=10.0'} + globals@17.11.0: + resolution: {integrity: sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==} + engines: {node: '>=18'} + globals@17.9.0: resolution: {integrity: sha512-m/MvAW61QVU5VDNF1Vj8axt016h8w7L5TU1e9zlab7XIttAT2YAlCwl75K1fOqvMM9apmD7lbCIRhpfkhmxhCg==} engines: {node: '>=18'} @@ -4065,8 +4137,8 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - hono@4.13.1: - resolution: {integrity: sha512-kdJoFVv2xmayw6cY09H7AbMJMt8Jn5jdlEdXsP7AGBdF2DIptVlKlOLKXP41yPip4/a3yQPv9gVcJYI8YY04dw==} + hono@4.13.3: + resolution: {integrity: sha512-r8AO2mYHoLxSHkgafNeC/BXyb2vWRxD3jem4Ts+ptav8oTG5FIRifAjuJEmZI4bSvvc2ns0GxmIYiZnHqN3mMw==} engines: {node: '>=16.9.0'} hosted-git-info@4.1.0: @@ -4142,8 +4214,8 @@ packages: inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} - input-otp@1.4.2: - resolution: {integrity: sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==} + input-otp@1.5.0: + resolution: {integrity: sha512-3AcfdW1sNG0FmSA5hHMBXG7jNW5CdcdKs8ln8JOmn6S2SRkoXoJx+2UwC+ZvjflfnOdHJx0SfQ9/YjlxVYLtGQ==} peerDependencies: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc @@ -4156,8 +4228,8 @@ packages: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} - ip-address@10.4.0: - resolution: {integrity: sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==} + ip-address@10.5.0: + resolution: {integrity: sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==} engines: {node: '>= 12'} ipaddr.js@1.9.1: @@ -4409,6 +4481,9 @@ packages: jose@6.2.8: resolution: {integrity: sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==} + jose@6.2.9: + resolution: {integrity: sha512-XrchZOFZUl/T3vTwRe8XK+cJrGtMF4th1ARnDfwbBXFKThGhlsxEE4Zu03AD/bjJSt/9jT/mxrOCkJWOg77aPA==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4695,8 +4770,8 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - lucide-react@1.31.0: - resolution: {integrity: sha512-G8u2eEtoHUnUa9f8lbvqDhCiORMnYLdUEo06EEG9MQvHQrInKcX3Pa2TH39MM5qyzRcWETxB0+aOwAPI1g1kEg==} + lucide-react@1.32.0: + resolution: {integrity: sha512-txX56hMFnRxPi1f9/nH69YN8uvAO6a7Y1KSWKjCDAtdD9+soEgmWuCt6iRm1pkxUZo2+YntSdsE1L6bIuKoY8Q==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -4962,9 +5037,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - mtp@https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz: - resolution: {integrity: sha512-WcXHd53aDM0zQfO8eaUnK5tpnRP73GlWjwAMMcstcVAIWrvyFGuINkCRNEkb2RsNk9h57UMhxElCZeBkFrVmCg==, tarball: https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz} - version: 0.2.0 + mtp@https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz: + resolution: {integrity: sha512-rI+xskgAp93o9EdBO/b7HnA0PZTQQPTYuF4Snon/hTvayN+x9O40oad4n/ZUF0ahS6grw00MPKPe89Mfe3BHnw==, tarball: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz} + version: 0.3.0 nanoid@3.3.18: resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} @@ -5065,8 +5140,8 @@ packages: oniguruma-to-es@4.3.6: resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} - open@11.0.0: - resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} + open@11.0.1: + resolution: {integrity: sha512-NzwMUB6C1D0+Kd+9iMS/H4k+Ck3cTX6Ckyfr/gAGlmvSE1LUQZnEZvWBi4PYmMwH/S5SMeTXnE+9uAz8uF+pWw==} engines: {node: '>=20'} open@8.4.2: @@ -5222,6 +5297,10 @@ packages: resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} engines: {node: '>=20'} + powershell-utils@0.2.0: + resolution: {integrity: sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==} + engines: {node: '>=20'} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -5351,8 +5430,8 @@ packages: '@types/react': optional: true - react-resizable-panels@4.12.2: - resolution: {integrity: sha512-NwY5LCo4WrxVvDh0xoMML6EMLPONP/8ckKcIdpnojxexoatZdjLiRqLJQjQK5CPkd4SYiB/2M5BVrjZBQtOO7Q==} + react-resizable-panels@4.12.3: + resolution: {integrity: sha512-GHMJWnDXui/3RX4bT+cgBP+N3N2nkwcoZATr/2xLFpqQQe7TlBrE0cGM0dUa9ceT7A90tUrSRsiqgRG+g0/2AA==} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 @@ -5378,8 +5457,8 @@ packages: readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - recast@0.23.19: - resolution: {integrity: sha512-T98lym7kH+pnZmRaD8yDRdaNqyUbwnbEBx0MuchrzMFOEMray4AO3ZJoTUZ5r78Ao78X/OhzW0DL8GB85w/I2w==} + recast@0.23.21: + resolution: {integrity: sha512-mFAyJq9vUbSTARLZUvAEf1z3YxlvAwswbmxMx2mPA/MSm4KmpwvwvhsH/NIrZhyOuwD60Lzyw2qh83uCbgTPYw==} engines: {node: '>= 4'} recharts@3.10.1: @@ -5632,8 +5711,8 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shadcn@4.16.2: - resolution: {integrity: sha512-M1AvZKFWcCzWRDoyApIqJMSLIpY8Ev4uBGuiPLSFmiTbixXhPmzotSTvLzFmBrfoIxG9aIg2dZOETblEaXGUnQ==} + shadcn@4.18.0: + resolution: {integrity: sha512-tUFZgkYmfVNQVm3xX7lhSzOvDsp+O14ac5dwgXIr5mIsr79ISueb/Mu+ZtWMz0DH6v77u4eYyvbQ9TTMpSn3aw==} engines: {node: '>=20.18.1'} hasBin: true @@ -5645,8 +5724,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@4.4.2: - resolution: {integrity: sha512-P8F/dFhRevaw2uSdeIYlq/5SXZNY85DPtmXQ947gD1Zj2JqO5AkNvVVBar0Me9JkFx3uzVud/qOtP5ek9NEQGA==} + shiki@4.4.3: + resolution: {integrity: sha512-Mb/GvXPHBAXdgGIcnfU5L3ldpn1XcxrGkPHwqgRx17/I2XRfqlFKk2vGkHWINn1kdXvzJZeuO3is6I9KLPFm0g==} engines: {node: '>=20'} side-channel-list@1.0.1: @@ -5682,10 +5761,18 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + smob@1.6.2: resolution: {integrity: sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==} engines: {node: '>=20.0.0'} + socks@2.8.9: + resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + sonner@2.0.7: resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} peerDependencies: @@ -5979,6 +6066,13 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + typescript-eslint@8.67.0: + resolution: {integrity: sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} @@ -6074,8 +6168,8 @@ packages: resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} engines: {node: '>=4'} - update-browserslist-db@1.3.0: - resolution: {integrity: sha512-x/M6q3w4Ybp91CNaS4S69UnliqR3BzRpOT6LWbksjth0S/+jhfaPJsWjt/TewpT8j9eLIojUf5jr29WextHroA==} + update-browserslist-db@1.3.1: + resolution: {integrity: sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -6201,20 +6295,20 @@ packages: yaml: optional: true - vitest@4.1.10: - resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} + vitest@4.1.11: + resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.10 - '@vitest/browser-preview': 4.1.10 - '@vitest/browser-webdriverio': 4.1.10 - '@vitest/coverage-istanbul': 4.1.10 - '@vitest/coverage-v8': 4.1.10 - '@vitest/ui': 4.1.10 + '@vitest/browser-playwright': 4.1.11 + '@vitest/browser-preview': 4.1.11 + '@vitest/browser-webdriverio': 4.1.11 + '@vitest/coverage-istanbul': 4.1.11 + '@vitest/coverage-v8': 4.1.11 + '@vitest/ui': 4.1.11 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -6356,8 +6450,8 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - wsl-utils@0.3.1: - resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} + wsl-utils@1.0.0: + resolution: {integrity: sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==} engines: {node: '>=20'} xmlbuilder@15.1.1: @@ -6493,7 +6587,7 @@ snapshots: dependencies: '@babel/compat-data': 7.29.7 '@babel/helper-validator-option': 7.29.7 - browserslist: 4.28.7 + browserslist: 4.28.8 lru-cache: 5.1.1 semver: 6.3.1 @@ -7173,14 +7267,14 @@ snapshots: dependencies: '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.8 + '@codemirror/view': 6.43.9 '@lezer/common': 1.5.2 - '@codemirror/commands@6.10.4': + '@codemirror/commands@6.11.0': dependencies: '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.8 + '@codemirror/view': 6.43.9 '@lezer/common': 1.5.2 '@codemirror/lang-css@6.3.1': @@ -7198,7 +7292,7 @@ snapshots: '@codemirror/lang-javascript': 6.2.5 '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.8 + '@codemirror/view': 6.43.9 '@lezer/common': 1.5.2 '@lezer/css': 1.3.6 '@lezer/html': 1.3.13 @@ -7209,7 +7303,7 @@ snapshots: '@codemirror/language': 6.12.4 '@codemirror/lint': 6.9.7 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.8 + '@codemirror/view': 6.43.9 '@lezer/common': 1.5.2 '@lezer/javascript': 1.5.4 @@ -7219,14 +7313,14 @@ snapshots: '@codemirror/lang-html': 6.4.12 '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.8 + '@codemirror/view': 6.43.9 '@lezer/common': 1.5.2 '@lezer/markdown': 1.7.2 '@codemirror/language@6.12.4': dependencies: '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.8 + '@codemirror/view': 6.43.9 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.10 @@ -7235,14 +7329,14 @@ snapshots: '@codemirror/lint@6.9.7': dependencies: '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.8 + '@codemirror/view': 6.43.9 crelt: 1.0.7 '@codemirror/state@6.7.1': dependencies: '@marijn/find-cluster-break': 1.0.3 - '@codemirror/view@6.43.8': + '@codemirror/view@6.43.9': dependencies: '@codemirror/state': 6.7.1 crelt: 1.0.7 @@ -7476,28 +7570,28 @@ snapshots: '@eslint/core': 1.2.1 levn: 0.4.1 - '@fallow-cli/darwin-arm64@3.14.0': + '@fallow-cli/darwin-arm64@3.17.0': optional: true - '@fallow-cli/darwin-x64@3.14.0': + '@fallow-cli/darwin-x64@3.17.0': optional: true - '@fallow-cli/linux-arm64-gnu@3.14.0': + '@fallow-cli/linux-arm64-gnu@3.17.0': optional: true - '@fallow-cli/linux-arm64-musl@3.14.0': + '@fallow-cli/linux-arm64-musl@3.17.0': optional: true - '@fallow-cli/linux-x64-gnu@3.14.0': + '@fallow-cli/linux-x64-gnu@3.17.0': optional: true - '@fallow-cli/linux-x64-musl@3.14.0': + '@fallow-cli/linux-x64-musl@3.17.0': optional: true - '@fallow-cli/win32-arm64-msvc@3.14.0': + '@fallow-cli/win32-arm64-msvc@3.17.0': optional: true - '@fallow-cli/win32-x64-msvc@3.14.0': + '@fallow-cli/win32-x64-msvc@3.17.0': optional: true '@floating-ui/core@1.8.0': @@ -7524,9 +7618,9 @@ snapshots: '@fontsource-variable/public-sans@5.3.0': {} - '@hono/node-server@2.1.0(hono@4.13.1)': + '@hono/node-server@2.1.1(hono@4.13.3)': dependencies: - hono: 4.13.1 + hono: 4.13.3 '@humanfs/core@0.19.2': dependencies: @@ -7652,12 +7746,12 @@ snapshots: dependencies: '@base-ui/react': 1.7.0(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@codemirror/autocomplete': 6.20.3 - '@codemirror/commands': 6.10.4 + '@codemirror/commands': 6.11.0 '@codemirror/lang-markdown': 6.5.2 '@codemirror/language': 6.12.4 '@codemirror/state': 6.7.1 - '@codemirror/view': 6.43.8 - '@shikijs/langs': 4.4.2 + '@codemirror/view': 6.43.9 + '@shikijs/langs': 4.4.3 '@tauri-apps/api': 2.11.1 class-variance-authority: 0.7.1 clsx: 2.1.1 @@ -7665,14 +7759,14 @@ snapshots: embla-carousel-react: 8.6.0(react@19.2.8) emojibase-data: 17.0.0(emojibase@17.0.0) hast-util-to-jsx-runtime: 2.3.6(supports-color@7.2.0) - input-otp: 1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + input-otp: 1.5.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) katex: 0.18.4 - lucide-react: 1.31.0(react@19.2.8) + lucide-react: 1.32.0(react@19.2.8) next-themes: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) react-markdown: 10.1.0(@types/react@19.2.18)(react@19.2.8)(supports-color@7.2.0) - react-resizable-panels: 4.12.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + react-resizable-panels: 4.12.3(react-dom@19.2.8(react@19.2.8))(react@19.2.8) recharts: 3.10.1(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1) rehype-autolink-headings: 7.1.0 rehype-katex: 7.0.1 @@ -7680,8 +7774,8 @@ snapshots: remark-breaks: 4.0.0 remark-gfm: 4.0.1(supports-color@7.2.0) remark-math: 6.0.0(supports-color@7.2.0) - shadcn: 4.16.2(supports-color@7.2.0)(typescript@6.0.3) - shiki: 4.4.2 + shadcn: 4.18.0(supports-color@7.2.0)(typescript@6.0.3) + shiki: 4.4.3 sonner: 2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) tailwind-merge: 3.6.0 tw-animate-css: 1.4.0 @@ -7702,18 +7796,18 @@ snapshots: '@modelcontextprotocol/sdk@1.30.0(supports-color@7.2.0)(zod@3.25.76)': dependencies: - '@hono/node-server': 2.1.0(hono@4.13.1) + '@hono/node-server': 2.1.1(hono@4.13.3) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 cors: 2.8.6 cross-spawn: 7.0.6 eventsource: 3.0.7 - eventsource-parser: 3.1.0 + eventsource-parser: 3.1.1 express: 5.2.1(supports-color@7.2.0) express-rate-limit: 8.6.2(express@5.2.1(supports-color@7.2.0))(supports-color@7.2.0) - hono: 4.13.1 - jose: 6.2.8 + hono: 4.13.3 + jose: 6.2.9 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 @@ -8078,40 +8172,40 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} - '@shikijs/core@4.4.2': + '@shikijs/core@4.4.3': dependencies: - '@shikijs/primitive': 4.4.2 - '@shikijs/types': 4.4.2 + '@shikijs/primitive': 4.4.3 + '@shikijs/types': 4.4.3 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.5 hast-util-to-html: 9.0.5 - '@shikijs/engine-javascript@4.4.2': + '@shikijs/engine-javascript@4.4.3': dependencies: - '@shikijs/types': 4.4.2 + '@shikijs/types': 4.4.3 '@shikijs/vscode-textmate': 10.0.2 oniguruma-to-es: 4.3.6 - '@shikijs/engine-oniguruma@4.4.2': + '@shikijs/engine-oniguruma@4.4.3': dependencies: - '@shikijs/types': 4.4.2 + '@shikijs/types': 4.4.3 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@4.4.2': + '@shikijs/langs@4.4.3': dependencies: - '@shikijs/types': 4.4.2 + '@shikijs/types': 4.4.3 - '@shikijs/primitive@4.4.2': + '@shikijs/primitive@4.4.3': dependencies: - '@shikijs/types': 4.4.2 + '@shikijs/types': 4.4.3 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.5 - '@shikijs/themes@4.4.2': + '@shikijs/themes@4.4.3': dependencies: - '@shikijs/types': 4.4.2 + '@shikijs/types': 4.4.3 - '@shikijs/types@4.4.2': + '@shikijs/types@4.4.3': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.5 @@ -8465,6 +8559,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/eslint-plugin@8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/type-utils': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.67.0 + eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + ignore: 7.0.6 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.66.0 @@ -8477,6 +8587,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.67.0 + debug: 4.4.3(supports-color@7.2.0) + eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/project-service@8.66.0(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.66.0(typescript@6.0.3) @@ -8486,15 +8608,33 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.67.0(supports-color@7.2.0)(typescript@6.0.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + debug: 4.4.3(supports-color@7.2.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.66.0': dependencies: '@typescript-eslint/types': 8.66.0 '@typescript-eslint/visitor-keys': 8.66.0 + '@typescript-eslint/scope-manager@8.67.0': + dependencies: + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/visitor-keys': 8.67.0 + '@typescript-eslint/tsconfig-utils@8.66.0(typescript@6.0.3)': dependencies: typescript: 6.0.3 + '@typescript-eslint/tsconfig-utils@8.67.0(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + '@typescript-eslint/type-utils@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.66.0 @@ -8507,8 +8647,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/type-utils@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + dependencies: + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + debug: 4.4.3(supports-color@7.2.0) + eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/types@8.66.0': {} + '@typescript-eslint/types@8.67.0': {} + '@typescript-eslint/typescript-estree@8.66.0(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@typescript-eslint/project-service': 8.66.0(supports-color@7.2.0)(typescript@6.0.3) @@ -8524,6 +8678,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.67.0(supports-color@7.2.0)(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/visitor-keys': 8.67.0 + debug: 4.4.3(supports-color@7.2.0) + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.66.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) @@ -8535,11 +8704,27 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0)) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) + eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/visitor-keys@8.66.0': dependencies: '@typescript-eslint/types': 8.66.0 eslint-visitor-keys: 5.0.1 + '@typescript-eslint/visitor-keys@8.67.0': + dependencies: + '@typescript-eslint/types': 8.67.0 + eslint-visitor-keys: 5.0.1 + '@typescript/typescript-aix-ppc64@7.0.2': optional: true @@ -8607,44 +8792,44 @@ snapshots: '@rolldown/pluginutils': 1.0.1 vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) - '@vitest/expect@4.1.10': + '@vitest/expect@4.1.11': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 chai: 6.2.2 tinyrainbow: 3.1.1 - '@vitest/mocker@4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.11(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.10 + '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) - '@vitest/pretty-format@4.1.10': + '@vitest/pretty-format@4.1.11': dependencies: tinyrainbow: 3.1.1 - '@vitest/runner@4.1.10': + '@vitest/runner@4.1.11': dependencies: - '@vitest/utils': 4.1.10 + '@vitest/utils': 4.1.11 pathe: 2.0.3 - '@vitest/snapshot@4.1.10': + '@vitest/snapshot@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.10 - '@vitest/utils': 4.1.10 + '@vitest/pretty-format': 4.1.11 + '@vitest/utils': 4.1.11 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.10': {} + '@vitest/spy@4.1.11': {} - '@vitest/utils@4.1.10': + '@vitest/utils@4.1.11': dependencies: - '@vitest/pretty-format': 4.1.10 + '@vitest/pretty-format': 4.1.11 convert-source-map: 2.0.0 tinyrainbow: 3.1.1 @@ -8691,7 +8876,7 @@ snapshots: ansi-regex@5.0.1: {} - ansi-regex@6.2.2: {} + ansi-regex@6.3.0: {} ansi-styles@4.3.0: dependencies: @@ -8828,14 +9013,14 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.11.12: {} + baseline-browser-mapping@2.11.15: {} bluebird@3.7.2: {} body-parser@2.3.0(supports-color@7.2.0): dependencies: bytes: 3.1.2 - content-type: 2.0.0 + content-type: 2.1.0 debug: 4.4.3(supports-color@7.2.0) http-errors: 2.0.1 iconv-lite: 0.7.3 @@ -8866,13 +9051,13 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.28.7: + browserslist@4.28.8: dependencies: - baseline-browser-mapping: 2.11.12 + baseline-browser-mapping: 2.11.15 caniuse-lite: 1.0.30001809 - electron-to-chromium: 1.5.402 + electron-to-chromium: 1.5.411 node-releases: 2.0.53 - update-browserslist-db: 1.3.0(browserslist@4.28.7) + update-browserslist-db: 1.3.1(browserslist@4.28.8) buffer-from@1.1.2: {} @@ -9054,7 +9239,7 @@ snapshots: content-type@1.0.5: {} - content-type@2.0.0: {} + content-type@2.1.0: {} convert-source-map@2.0.0: {} @@ -9066,7 +9251,7 @@ snapshots: core-js-compat@3.50.0: dependencies: - browserslist: 4.28.7 + browserslist: 4.28.8 core-util-is@1.0.3: {} @@ -9189,7 +9374,7 @@ snapshots: default-browser-id@5.0.1: {} - default-browser@5.5.0: + default-browser@5.5.1: dependencies: bundle-name: 4.1.0 default-browser-id: 5.0.1 @@ -9313,7 +9498,7 @@ snapshots: transitivePeerDependencies: - supports-color - electron-to-chromium@1.5.402: {} + electron-to-chromium@1.5.411: {} electron-winstaller@5.4.0(supports-color@7.2.0): dependencies: @@ -9453,7 +9638,7 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@2.3.1: {} + es-module-lexer@2.3.2: {} es-object-atoms@1.1.2: dependencies: @@ -9612,11 +9797,11 @@ snapshots: events@3.3.0: {} - eventsource-parser@3.1.0: {} + eventsource-parser@3.1.1: {} eventsource@3.0.7: dependencies: - eventsource-parser: 3.1.0 + eventsource-parser: 3.1.1 execa@5.1.1: dependencies: @@ -9653,7 +9838,7 @@ snapshots: dependencies: debug: 4.4.3(supports-color@7.2.0) express: 5.2.1(supports-color@7.2.0) - ip-address: 10.4.0 + ip-address: 10.5.0 transitivePeerDependencies: - supports-color @@ -9692,24 +9877,24 @@ snapshots: extend@3.0.2: {} - fallow-type-aware@3.14.0: + fallow-type-aware@3.17.0: dependencies: typescript: 7.0.2 optional: true - fallow@3.14.0: + fallow@3.17.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - '@fallow-cli/darwin-arm64': 3.14.0 - '@fallow-cli/darwin-x64': 3.14.0 - '@fallow-cli/linux-arm64-gnu': 3.14.0 - '@fallow-cli/linux-arm64-musl': 3.14.0 - '@fallow-cli/linux-x64-gnu': 3.14.0 - '@fallow-cli/linux-x64-musl': 3.14.0 - '@fallow-cli/win32-arm64-msvc': 3.14.0 - '@fallow-cli/win32-x64-msvc': 3.14.0 - fallow-type-aware: 3.14.0 + '@fallow-cli/darwin-arm64': 3.17.0 + '@fallow-cli/darwin-x64': 3.17.0 + '@fallow-cli/linux-arm64-gnu': 3.17.0 + '@fallow-cli/linux-arm64-musl': 3.17.0 + '@fallow-cli/linux-x64-gnu': 3.17.0 + '@fallow-cli/linux-x64-musl': 3.17.0 + '@fallow-cli/win32-arm64-msvc': 3.17.0 + '@fallow-cli/win32-x64-msvc': 3.17.0 + fallow-type-aware: 3.17.0 fast-deep-equal@3.1.3: {} @@ -9955,6 +10140,8 @@ snapshots: serialize-error: 7.0.1 optional: true + globals@17.11.0: {} + globals@17.9.0: {} globalthis@1.0.4: @@ -10110,7 +10297,7 @@ snapshots: dependencies: hermes-estree: 0.25.1 - hono@4.13.1: {} + hono@4.13.3: {} hosted-git-info@4.1.0: dependencies: @@ -10181,7 +10368,7 @@ snapshots: inline-style-parser@0.2.7: {} - input-otp@1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + input-otp@1.5.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) @@ -10194,7 +10381,7 @@ snapshots: internmap@2.0.3: {} - ip-address@10.4.0: {} + ip-address@10.5.0: {} ipaddr.js@1.9.1: {} @@ -10399,6 +10586,8 @@ snapshots: jose@6.2.8: {} + jose@6.2.9: {} + js-tokens@4.0.0: {} js-yaml@4.3.1: @@ -10616,7 +10805,7 @@ snapshots: dependencies: react: 19.2.8 - lucide-react@1.31.0(react@19.2.8): + lucide-react@1.32.0(react@19.2.8): dependencies: react: 19.2.8 @@ -11085,7 +11274,7 @@ snapshots: ms@2.1.3: {} - mtp@https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz: + mtp@https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz: dependencies: yaml: 2.9.0 @@ -11183,14 +11372,14 @@ snapshots: regex: 6.1.0 regex-recursion: 6.0.2 - open@11.0.0: + open@11.0.1: dependencies: - default-browser: 5.5.0 + default-browser: 5.5.1 define-lazy-prop: 3.0.0 is-in-ssh: 1.0.0 is-inside-container: 1.0.0 - powershell-utils: 0.1.0 - wsl-utils: 0.3.1 + powershell-utils: 0.2.0 + wsl-utils: 1.0.0 open@8.4.2: dependencies: @@ -11349,6 +11538,8 @@ snapshots: powershell-utils@0.1.0: {} + powershell-utils@0.2.0: {} + prelude-ls@1.2.1: {} prettier@3.9.6: {} @@ -11474,7 +11665,7 @@ snapshots: optionalDependencies: '@types/react': 19.2.18 - react-resizable-panels@4.12.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + react-resizable-panels@4.12.3(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) @@ -11505,7 +11696,7 @@ snapshots: string_decoder: 1.1.1 util-deprecate: 1.0.2 - recast@0.23.19: + recast@0.23.21: dependencies: ast-types: 0.16.1 esprima: 4.0.1 @@ -11894,7 +12085,7 @@ snapshots: setprototypeof@1.2.0: {} - shadcn@4.16.2(supports-color@7.2.0)(typescript@6.0.3): + shadcn@4.18.0(supports-color@7.2.0)(typescript@6.0.3): dependencies: '@babel/core': 7.29.7(supports-color@7.2.0) '@babel/parser': 7.29.8 @@ -11903,7 +12094,7 @@ snapshots: '@dotenvx/dotenvx': 1.75.1 '@modelcontextprotocol/sdk': 1.30.0(supports-color@7.2.0)(zod@3.25.76) '@types/validate-npm-package-name': 4.0.2 - browserslist: 4.28.7 + browserslist: 4.28.8 commander: 14.0.3 cosmiconfig: 9.0.2(typescript@6.0.3) dedent: 1.7.2 @@ -11914,12 +12105,13 @@ snapshots: fs-extra: 11.4.0 fuzzysort: 3.1.0 kleur: 4.1.5 - open: 11.0.0 + open: 11.0.1 ora: 8.2.0 postcss: 8.5.26 postcss-selector-parser: 7.1.5 prompts: 2.4.2 - recast: 0.23.19 + recast: 0.23.21 + socks: 2.8.9 stringify-object: 5.0.0 tailwind-merge: 3.6.0 ts-morph: 26.0.0 @@ -11940,14 +12132,14 @@ snapshots: shebang-regex@3.0.0: {} - shiki@4.4.2: + shiki@4.4.3: dependencies: - '@shikijs/core': 4.4.2 - '@shikijs/engine-javascript': 4.4.2 - '@shikijs/engine-oniguruma': 4.4.2 - '@shikijs/langs': 4.4.2 - '@shikijs/themes': 4.4.2 - '@shikijs/types': 4.4.2 + '@shikijs/core': 4.4.3 + '@shikijs/engine-javascript': 4.4.3 + '@shikijs/engine-oniguruma': 4.4.3 + '@shikijs/langs': 4.4.3 + '@shikijs/themes': 4.4.3 + '@shikijs/types': 4.4.3 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.5 @@ -11991,8 +12183,15 @@ snapshots: sisteransi@1.0.5: {} + smart-buffer@4.2.0: {} + smob@1.6.2: {} + socks@2.8.9: + dependencies: + ip-address: 10.5.0 + smart-buffer: 4.2.0 + sonner@2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: react: 19.2.8 @@ -12115,7 +12314,7 @@ snapshots: strip-ansi@7.2.0: dependencies: - ansi-regex: 6.2.2 + ansi-regex: 6.3.0 strip-bom@3.0.0: {} @@ -12260,7 +12459,7 @@ snapshots: type-is@2.1.0: dependencies: - content-type: 2.0.0 + content-type: 2.1.0 media-typer: 1.1.1 mime-types: 3.0.2 @@ -12312,6 +12511,17 @@ snapshots: transitivePeerDependencies: - supports-color + typescript-eslint@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.67.0(supports-color@7.2.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.8.1(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) + eslint: 10.8.1(jiti@2.7.0)(supports-color@7.2.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + typescript@6.0.3: {} typescript@7.0.2: @@ -12429,9 +12639,9 @@ snapshots: upath@1.2.0: {} - update-browserslist-db@1.3.0(browserslist@4.28.7): + update-browserslist-db@1.3.1(browserslist@4.28.8): dependencies: - browserslist: 4.28.7 + browserslist: 4.28.8 escalade: 3.2.0 picocolors: 1.1.1 @@ -12538,16 +12748,16 @@ snapshots: terser: 5.50.0 yaml: 2.9.0 - vitest@4.1.10(@types/node@26.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0)): + vitest@4.1.11(@types/node@26.2.0)(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.10 - '@vitest/runner': 4.1.10 - '@vitest/snapshot': 4.1.10 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 - es-module-lexer: 2.3.1 + '@vitest/expect': 4.1.11 + '@vitest/mocker': 4.1.11(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.11 + '@vitest/runner': 4.1.11 + '@vitest/snapshot': 4.1.11 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 + es-module-lexer: 2.3.2 expect-type: 1.4.0 magic-string: 0.30.21 obug: 2.1.4 @@ -12766,7 +12976,7 @@ snapshots: wrappy@1.0.2: {} - wsl-utils@0.3.1: + wsl-utils@1.0.0: dependencies: is-wsl: 3.1.1 powershell-utils: 0.1.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ee3c57a..f713a2d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -7,4 +7,4 @@ allowBuilds: esbuild: true overrides: "@methanium/ui": "https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz" - mtp: "https://git.methanium.net/methanium/mtp/releases/download/0.2.0-dev-a692bed/mtp-0.2.0.tgz" + mtp: "https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz" diff --git a/utils/scripts/build-packages.ts b/utils/scripts/build-packages.ts index 9518c49..1f1f4fd 100644 --- a/utils/scripts/build-packages.ts +++ b/utils/scripts/build-packages.ts @@ -15,7 +15,14 @@ function getPackageDirs(dir: string): string[] { for (const entry of entries) { const fullPath = join(dir, entry); - if (!statSync(fullPath).isDirectory()) continue; + if (entry === "node_modules" || entry.startsWith(".")) continue; + let stats; + try { + stats = statSync(fullPath); + } catch { + continue; + } + if (!stats.isDirectory()) continue; if (existsSync(join(fullPath, "package.json"))) { dirs.push(fullPath); diff --git a/utils/scripts/lint-packages.ts b/utils/scripts/lint-packages.ts index 0aea8c3..c84e0e0 100644 --- a/utils/scripts/lint-packages.ts +++ b/utils/scripts/lint-packages.ts @@ -16,7 +16,14 @@ function getPackageDirs(dir: string): string[] { for (const entry of entries) { const fullPath = join(dir, entry); - if (!statSync(fullPath).isDirectory()) continue; + if (entry === "node_modules" || entry.startsWith(".")) continue; + let stats; + try { + stats = statSync(fullPath); + } catch { + continue; + } + if (!stats.isDirectory()) continue; if (existsSync(join(fullPath, "package.json"))) { dirs.push(fullPath); diff --git a/utils/scripts/update-packages.ts b/utils/scripts/update-packages.ts index 22b258f..90b3b0c 100644 --- a/utils/scripts/update-packages.ts +++ b/utils/scripts/update-packages.ts @@ -15,7 +15,14 @@ function getPackageDirs(dir: string): string[] { for (const entry of entries) { const fullPath = join(dir, entry); - if (!statSync(fullPath).isDirectory()) continue; + if (entry === "node_modules" || entry.startsWith(".")) continue; + let stats; + try { + stats = statSync(fullPath); + } catch { + continue; + } + if (!stats.isDirectory()) continue; if (existsSync(join(fullPath, "package.json"))) { dirs.push(fullPath); From 97270abed80469c2d26419996076c937a2744f85 Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 20 Aug 2026 20:56:30 +0200 Subject: [PATCH 84/97] Update workflows --- .forgejo/workflows/dependency-builds.yml | 4 ---- .forgejo/workflows/deploy-dev.yml | 14 -------------- .forgejo/workflows/deploy-prod.yml | 14 -------------- 3 files changed, 32 deletions(-) diff --git a/.forgejo/workflows/dependency-builds.yml b/.forgejo/workflows/dependency-builds.yml index 709c75b..153ea73 100644 --- a/.forgejo/workflows/dependency-builds.yml +++ b/.forgejo/workflows/dependency-builds.yml @@ -4,7 +4,6 @@ on: pull_request: env: - NIX_CONFIG: experimental-features = nix-command flakes FORGEJO_TOKEN: "" GITHUB_TOKEN: "" @@ -14,7 +13,6 @@ jobs: name: Build web runs-on: nixos steps: - - run: nix profile add nixpkgs#nodejs_24 - uses: https://data.forgejo.org/actions/checkout@v4 with: persist-credentials: false @@ -28,7 +26,6 @@ jobs: name: Build desktop runs-on: nixos steps: - - run: nix profile add nixpkgs#nodejs_24 - uses: https://data.forgejo.org/actions/checkout@v4 with: persist-credentials: false @@ -42,7 +39,6 @@ jobs: name: Build mobile runs-on: nixos steps: - - run: nix profile add nixpkgs#nodejs_24 - uses: https://data.forgejo.org/actions/checkout@v4 with: persist-credentials: false diff --git a/.forgejo/workflows/deploy-dev.yml b/.forgejo/workflows/deploy-dev.yml index 0d5be50..27252b2 100644 --- a/.forgejo/workflows/deploy-dev.yml +++ b/.forgejo/workflows/deploy-dev.yml @@ -12,9 +12,6 @@ jobs: build-web: runs-on: nixos steps: - - name: Install node - run: nix profile add nixpkgs#nodejs_24 - - name: Check out repo uses: https://data.forgejo.org/actions/checkout@v4 @@ -39,9 +36,6 @@ jobs: build-mobile: runs-on: nixos steps: - - name: Install node - run: nix profile add nixpkgs#nodejs_24 - - name: Check out repo uses: https://data.forgejo.org/actions/checkout@v4 @@ -62,8 +56,6 @@ jobs: KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} KEYSTORE_PROPERTIES: ${{ secrets.ANDROID_KEYSTORE_PROPERTIES }} run: | - nix profile add nixpkgs#gnused - set -euo pipefail if [ -z "$KEYSTORE_BASE64" ]; then @@ -128,9 +120,6 @@ jobs: matrix: target: [linux] steps: - - name: Install node - run: nix profile add nixpkgs#nodejs_24 - - name: Check out repo uses: https://data.forgejo.org/actions/checkout@v4 @@ -181,9 +170,6 @@ jobs: runs-on: nixos needs: [build-web, build-mobile, build-desktop] steps: - - name: Install node - run: nix profile add nixpkgs#nodejs_24 - - name: Check out repo uses: https://data.forgejo.org/actions/checkout@v4 with: diff --git a/.forgejo/workflows/deploy-prod.yml b/.forgejo/workflows/deploy-prod.yml index d85ce27..0bb5887 100644 --- a/.forgejo/workflows/deploy-prod.yml +++ b/.forgejo/workflows/deploy-prod.yml @@ -13,9 +13,6 @@ jobs: build-web: runs-on: nixos steps: - - name: Install node - run: nix profile add nixpkgs#nodejs_24 - - name: Check out repo uses: https://data.forgejo.org/actions/checkout@v4 @@ -40,9 +37,6 @@ jobs: build-mobile: runs-on: nixos steps: - - name: Install node - run: nix profile add nixpkgs#nodejs_24 - - name: Check out repo uses: https://data.forgejo.org/actions/checkout@v4 @@ -63,8 +57,6 @@ jobs: KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} KEYSTORE_PROPERTIES: ${{ secrets.ANDROID_KEYSTORE_PROPERTIES }} run: | - nix profile add nixpkgs#gnused - set -euo pipefail if [ -z "$KEYSTORE_BASE64" ]; then @@ -129,9 +121,6 @@ jobs: matrix: target: [linux] steps: - - name: Install node - run: nix profile add nixpkgs#nodejs_24 - - name: Check out repo uses: https://data.forgejo.org/actions/checkout@v4 @@ -180,9 +169,6 @@ jobs: runs-on: nixos needs: [build-web, build-mobile, build-desktop] steps: - - name: Install node - run: nix profile add nixpkgs#nodejs_24 - - name: Check out repo uses: https://data.forgejo.org/actions/checkout@v4 From 88a094c8bfdc9a99381f64bff83bb90825f7623b Mon Sep 17 00:00:00 2001 From: Alois Date: Tue, 25 Aug 2026 20:46:14 +0200 Subject: [PATCH 85/97] feat(pwa): remove update toast --- apps/electron/build/icons/128x128.png | Bin 14041 -> 0 bytes apps/electron/build/icons/128x128@2x.png | Bin 22479 -> 0 bytes apps/electron/build/icons/32x32.png | Bin 2320 -> 0 bytes apps/electron/build/icons/64x64.png | Bin 5757 -> 0 bytes apps/electron/build/icons/icon.icns | Bin 257363 -> 0 bytes apps/electron/build/icons/icon.ico | Bin 37998 -> 0 bytes apps/electron/build/icons/icon.png | Bin 41711 -> 0 bytes apps/pwa/src/runtime.tsx | 8 - packages/markdown/package.json | 30 + packages/markdown/src/emoji.tsx | 50 ++ packages/markdown/src/emojiData.ts | 94 +++ packages/markdown/src/input.tsx | 850 +++++++++++++++++++++++ packages/markdown/src/markdown.tsx | 815 ++++++++++++++++++++++ packages/markdown/src/text.tsx | 30 + packages/markdown/todo.md | 1 + packages/markdown/tsconfig.json | 12 + pnpm-lock.yaml | 63 ++ 17 files changed, 1945 insertions(+), 8 deletions(-) delete mode 100644 apps/electron/build/icons/128x128.png delete mode 100644 apps/electron/build/icons/128x128@2x.png delete mode 100644 apps/electron/build/icons/32x32.png delete mode 100644 apps/electron/build/icons/64x64.png delete mode 100644 apps/electron/build/icons/icon.icns delete mode 100644 apps/electron/build/icons/icon.ico delete mode 100644 apps/electron/build/icons/icon.png create mode 100644 packages/markdown/package.json create mode 100644 packages/markdown/src/emoji.tsx create mode 100644 packages/markdown/src/emojiData.ts create mode 100644 packages/markdown/src/input.tsx create mode 100644 packages/markdown/src/markdown.tsx create mode 100644 packages/markdown/src/text.tsx create mode 100644 packages/markdown/todo.md create mode 100644 packages/markdown/tsconfig.json diff --git a/apps/electron/build/icons/128x128.png b/apps/electron/build/icons/128x128.png deleted file mode 100644 index 357e1c2a4faa748fde46c79bbddab4bae04d05d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14041 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ⅆ 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 diff --git a/apps/electron/build/icons/icon.icns b/apps/electron/build/icons/icon.icns deleted file mode 100644 index a7f0a1e940bbdd0f4c8b453dc3ff837603c4dc08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 257363 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

    l6`H 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ⅆ&9z8LqNY;8W0LUaDGtXnOMj)@3Og%$ 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%0AwIQn~ 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 diff --git a/apps/electron/build/icons/icon.ico b/apps/electron/build/icons/icon.ico deleted file mode 100644 index c5c68f820df524e5a23ecdd2a569d8874bbedf65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37998 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 CvgwuP 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 P0|SGntDnm{r-UW|U4bl% diff --git a/apps/pwa/src/runtime.tsx b/apps/pwa/src/runtime.tsx index 21c2556..5d78973 100644 --- a/apps/pwa/src/runtime.tsx +++ b/apps/pwa/src/runtime.tsx @@ -94,15 +94,7 @@ export default function PwaRuntime() { if (worker.state !== "installed") return; if (!navigator.serviceWorker.controller) { toast.success("Tensamin is ready for offline startup"); - return; } - toast("A Tensamin update is ready", { - duration: Infinity, - action: { - label: "Update", - onClick: () => worker.postMessage({ type: "SKIP_WAITING" }), - }, - }); }); }; if (registration.installing) watchWorker(registration.installing); diff --git a/packages/markdown/package.json b/packages/markdown/package.json new file mode 100644 index 0000000..247d715 --- /dev/null +++ b/packages/markdown/package.json @@ -0,0 +1,30 @@ +{ + "name": "@tensamin/markdown", + "private": true, + "version": "0.0.0", + "type": "module", + "exports": { + "./text": "./src/text.tsx", + "./input": "./src/input.tsx", + "./emoji": "./src/emoji.tsx" + }, + "scripts": { + "format": "pnpm exec prettier --write .", + "lint": "eslint src", + "build": "tsc -p tsconfig.json --noEmit" + }, + "dependencies": { + "@codemirror/autocomplete": "^6.20.3", + "@codemirror/commands": "^6.10.4", + "@codemirror/lang-markdown": "^6.5.2", + "@codemirror/language": "^6.12.4", + "@codemirror/state": "^6.7.1", + "@codemirror/view": "^6.43.8", + "@methanium/ui": "*", + "@twemoji/api": "^17.0.3", + "emojibase-data": "^17.0.0", + "lucide-react": "^1.30.0", + "react": "^19.2.8", + "react-dom": "^19.2.8" + } +} diff --git a/packages/markdown/src/emoji.tsx b/packages/markdown/src/emoji.tsx new file mode 100644 index 0000000..c0eb397 --- /dev/null +++ b/packages/markdown/src/emoji.tsx @@ -0,0 +1,50 @@ +import twemoji from "@twemoji/api"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@methanium/ui"; +import { resolveEmoji } from "./emojiData"; + +export { + emojis, + findEmojiShortcodes, + normalizeShortcode, + resolveEmoji, + searchEmojis, +} from "./emojiData"; +export type { EmojiDefinition } from "./emojiData"; + +export function getEmojiUrl(shortcode: string): string | undefined { + const emoji = resolveEmoji(shortcode); + return emoji ? `${twemoji.base}svg/${emoji.hexcode}.svg` : undefined; +} + +export default function Emoji({ + className = "h-6 w-6", + shortcode, + tooltip = true, +}: { + className?: string; + shortcode: string; + tooltip?: boolean; +}) { + const emoji = resolveEmoji(shortcode); + if (!emoji) return {shortcode}; + + const image = ( + {emoji.shortcode} + ); + + if (!tooltip) return image; + + return ( + + + {emoji.shortcode} + + ); +} diff --git a/packages/markdown/src/emojiData.ts b/packages/markdown/src/emojiData.ts new file mode 100644 index 0000000..158b5b0 --- /dev/null +++ b/packages/markdown/src/emojiData.ts @@ -0,0 +1,94 @@ +import shortcodeData from "emojibase-data/en/shortcodes/joypixels.json"; + +export type EmojiDefinition = { + aliases: readonly string[]; + hexcode: string; + name: string; + shortcode: string; +}; + +function normalizeName(value: string) { + return value + .trim() + .replace(/^:+|:+$/g, "") + .toLowerCase(); +} + +export const emojis: readonly EmojiDefinition[] = Object.entries( + shortcodeData as Record, +).map(([hexcode, value]) => { + const aliases = Array.isArray(value) ? value : [value]; + const name = aliases[0]; + + return { + aliases, + hexcode: hexcode.toLowerCase().replaceAll("_", "-"), + name, + shortcode: `:${name}:`, + }; +}); + +const emojiByName = new Map(); +for (const emoji of emojis) { + for (const alias of emoji.aliases) { + emojiByName.set(normalizeName(alias), emoji); + } +} + +export function resolveEmoji(value: string): EmojiDefinition | undefined { + return emojiByName.get(normalizeName(value)); +} + +export function normalizeShortcode(value: string): string | undefined { + return resolveEmoji(value)?.shortcode; +} + +export function findEmojiShortcodes(value: string) { + const matches: Array<{ + emoji: EmojiDefinition; + from: number; + to: number; + }> = []; + let searchFrom = 0; + + while (searchFrom < value.length) { + const from = value.indexOf(":", searchFrom); + if (from === -1) break; + + const candidate = value.slice(from).match(/^:([a-z0-9_+-]+):/i); + if (!candidate) { + searchFrom = from + 1; + continue; + } + + const emoji = resolveEmoji(candidate[1]); + if (!emoji) { + // The closing colon may also open the next valid shortcode. + searchFrom = from + candidate[0].length - 1; + continue; + } + + const to = from + candidate[0].length; + matches.push({ emoji, from, to }); + searchFrom = to; + } + + return matches; +} + +export function searchEmojis(query: string): EmojiDefinition[] { + const normalizedQuery = normalizeName(query); + if (!normalizedQuery) return [...emojis]; + + return emojis + .map((emoji) => { + const names = emoji.aliases.map(normalizeName); + const exact = names.includes(normalizedQuery); + const prefix = names.some((name) => name.startsWith(normalizedQuery)); + const contains = names.some((name) => name.includes(normalizedQuery)); + return { emoji, rank: exact ? 0 : prefix ? 1 : contains ? 2 : 3 }; + }) + .filter(({ rank }) => rank < 3) + .sort((a, b) => a.rank - b.rank || a.emoji.name.localeCompare(b.emoji.name)) + .map(({ emoji }) => emoji); +} diff --git a/packages/markdown/src/input.tsx b/packages/markdown/src/input.tsx new file mode 100644 index 0000000..e16c84d --- /dev/null +++ b/packages/markdown/src/input.tsx @@ -0,0 +1,850 @@ +import { markdown } from "@codemirror/lang-markdown"; +import { syntaxTree } from "@codemirror/language"; +import { + acceptCompletion, + autocompletion, + completionStatus, + pickedCompletion, + startCompletion, + type Completion, + type CompletionContext, + type CompletionResult, +} from "@codemirror/autocomplete"; +import { + EditorState, + EditorSelection, + Annotation, + Compartment, + Prec, + Transaction, + type Extension, + type Range, + type SelectionRange, +} from "@codemirror/state"; +import { + Decoration, + EditorView, + keymap, + placeholder, + ViewPlugin, + WidgetType, + type DecorationSet, + type KeyBinding, + type ViewUpdate, +} from "@codemirror/view"; +import { + defaultKeymap, + history, + historyKeymap, + indentWithTab, +} from "@codemirror/commands"; +import { useEffect, useRef } from "react"; +import type { CSSProperties } from "react"; +import { createRoot, type Root } from "react-dom/client"; + +import { collectInlineRanges, ensureMarkdownStyles } from "./markdown"; +import Emoji, { + findEmojiShortcodes, + getEmojiUrl, + resolveEmoji, + searchEmojis, +} from "./emoji"; + +export const MAX_RENDERED_EMOJI_OPTIONS = 100; + +export type InputController = { + focus: () => void; + hasFocus: () => boolean; + insertText: (text: string) => void; +}; + +export type InputProps = { + ref?: HTMLDivElement; + placeholder?: string; + value: string; + setValue: (value: string) => void; + onSubmit?: () => void; + invertEnterBehavior?: boolean; + styled?: boolean; + fontSize?: CSSProperties["fontSize"]; + paddingX?: CSSProperties["padding"]; + paddingY?: CSSProperties["padding"]; + className?: string; + emojiFrequencies?: Readonly>; + onEmojiSelect?: (shortcode: string) => void; + autoFocus?: boolean; + onControllerChange?: (controller: InputController | null) => void; +}; + +function toCssLength(value: CSSProperties["padding"]): string | undefined { + if (value === undefined) { + return undefined; + } + + return typeof value === "number" ? `${value}px` : value; +} + +function toCssPadding( + vertical: CSSProperties["padding"], + horizontal: CSSProperties["padding"], + styled: boolean, +): string { + const defaultVertical = styled ? "0.25rem" : "0"; + const defaultHorizontal = styled ? "0.625rem" : "0"; + + return `${toCssLength(vertical) ?? defaultVertical} ${toCssLength(horizontal) ?? defaultHorizontal}`; +} + +const hiddenTokenDecoration = Decoration.mark({ class: "tm-md-hidden-token" }); +const strongDecoration = Decoration.mark({ class: "tm-md-strong" }); +const emDecoration = Decoration.mark({ class: "tm-md-em" }); +const delDecoration = Decoration.mark({ class: "tm-md-del" }); +const codeDecoration = Decoration.mark({ class: "tm-md-code" }); +const linkDecoration = Decoration.mark({ class: "tm-md-link" }); +const codeLineDecoration = Decoration.line({ class: "tm-md-code-line" }); +const externalValueSync = Annotation.define(); +const widgetRoots = new WeakMap(); + +type EmojiRange = { + from: number; + shortcode: string; + to: number; + url: string; +}; + +class EmojiWidget extends WidgetType { + readonly shortcode: string; + readonly url: string; + + constructor(shortcode: string, url: string) { + super(); + this.shortcode = shortcode; + this.url = url; + } + + eq(other: EmojiWidget) { + return other.shortcode === this.shortcode && other.url === this.url; + } + + toDOM() { + const container = document.createElement("span"); + const root = createRoot(container); + root.render( + , + ); + widgetRoots.set(container, root); + return container; + } + + destroy(dom: HTMLElement) { + widgetRoots.get(dom)?.unmount(); + widgetRoots.delete(dom); + } + + ignoreEvent() { + return true; + } +} + +function codeRanges(state: EditorState) { + const ranges: Array<{ from: number; to: number }> = []; + + syntaxTree(state).iterate({ + enter(node) { + if ( + node.name === "InlineCode" || + node.name === "FencedCode" || + node.name === "CodeBlock" + ) { + ranges.push({ from: node.from, to: node.to }); + return false; + } + }, + }); + + return ranges; +} + +export function findEmojiRanges(state: EditorState): EmojiRange[] { + const document = state.doc.toString(); + const excluded = codeRanges(state); + const ranges: EmojiRange[] = []; + + for (const match of findEmojiShortcodes(document)) { + const { from, to } = match; + const inCode = excluded.some((range) => from < range.to && to > range.from); + const emoji = inCode ? undefined : match.emoji; + const url = emoji ? getEmojiUrl(emoji.shortcode) : undefined; + + if (emoji && url) { + ranges.push({ from, shortcode: emoji.shortcode, to, url }); + } + } + + return ranges; +} + +class EmojiPluginValue { + decorations: DecorationSet; + ranges: EmojiRange[]; + + constructor(view: EditorView) { + this.ranges = findEmojiRanges(view.state); + this.decorations = this.buildDecorations(); + } + + update(update: ViewUpdate) { + if ( + update.docChanged || + syntaxTree(update.startState) !== syntaxTree(update.state) + ) { + this.ranges = findEmojiRanges(update.state); + this.decorations = this.buildDecorations(); + } + } + + private buildDecorations() { + return Decoration.set( + this.ranges.map((range) => + Decoration.replace({ + inclusive: false, + widget: new EmojiWidget(range.shortcode, range.url), + }).range(range.from, range.to), + ), + true, + ); + } +} + +const emojiDecorations = ViewPlugin.fromClass(EmojiPluginValue, { + decorations: (instance) => instance.decorations, + provide: (plugin) => + EditorView.atomicRanges.of( + (view) => view.plugin(plugin)?.decorations ?? Decoration.none, + ), +}); + +function deleteEmoji(view: EditorView, direction: "backward" | "forward") { + const ranges = view.plugin(emojiDecorations)?.ranges ?? []; + const deletions: Array<{ from: number; to: number }> = []; + + for (const selection of view.state.selection.ranges) { + if (selection.empty) { + const emoji = ranges.find((range) => + direction === "backward" + ? selection.from > range.from && selection.from <= range.to + : selection.from >= range.from && selection.from < range.to, + ); + if (emoji) deletions.push({ from: emoji.from, to: emoji.to }); + continue; + } + + let from = selection.from; + let to = selection.to; + let changed = false; + + for (const emoji of ranges) { + if (from < emoji.to && to > emoji.from) { + from = Math.min(from, emoji.from); + to = Math.max(to, emoji.to); + changed = true; + } + } + + if (changed) deletions.push({ from, to }); + } + + if (deletions.length === 0) return false; + + const merged = deletions + .sort((a, b) => a.from - b.from) + .reduce>((result, deletion) => { + const previous = result.at(-1); + if (previous && deletion.from <= previous.to) { + previous.to = Math.max(previous.to, deletion.to); + } else { + result.push({ ...deletion }); + } + return result; + }, []); + + view.dispatch({ + changes: merged.map((range) => ({ from: range.from, to: range.to })), + selection: EditorSelection.cursor(merged[0].from), + scrollIntoView: true, + userEvent: direction === "backward" ? "delete.backward" : "delete.forward", + }); + return true; +} + +/** + * Builds markdown styling decorations every time the document or cursor selection changes. + * Token delimiters are hidden unless the cursor is currently intersecting that token range. + */ +const markdownDecorations = ViewPlugin.fromClass( + class { + decorations: DecorationSet; + + constructor(view: EditorView) { + this.decorations = buildDecorations(view); + } + + update(update: ViewUpdate) { + if (update.docChanged || update.selectionSet || update.viewportChanged) { + this.decorations = buildDecorations(update.view); + } + } + }, + { + decorations: (instance: { decorations: DecorationSet }) => + instance.decorations, + }, +); + +/** + * Executes Input. + * @param props Parameter props. + * @returns unknown. + */ +export default function Input(props: InputProps) { + ensureMarkdownStyles(); + + const shellClassName = props.styled + ? "min-h-8 w-full min-w-0 rounded-lg border border-input bg-transparent text-base transition-colors outline-none placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40" + : ""; + + const elementRef = useRef(null); + const viewRef = useRef(undefined); + const setValueRef = useRef(props.setValue); + const onSubmitRef = useRef(props.onSubmit); + const onEmojiSelectRef = useRef( + props.onEmojiSelect, + ); + const invertEnterBehaviorRef = useRef(Boolean(props.invertEnterBehavior)); + const completionCompartmentRef = useRef(null); + completionCompartmentRef.current ??= new Compartment(); + const completionCompartment = completionCompartmentRef.current; + + useEffect(() => { + setValueRef.current = props.setValue; + onSubmitRef.current = props.onSubmit; + onEmojiSelectRef.current = props.onEmojiSelect; + invertEnterBehaviorRef.current = Boolean(props.invertEnterBehavior); + }, [ + props.onEmojiSelect, + props.onSubmit, + props.invertEnterBehavior, + props.setValue, + ]); + + useEffect(() => { + if (!elementRef.current) return; + + const state = EditorState.create({ + doc: props.value, + extensions: createEditorExtensions( + (value) => { + setValueRef.current(value); + }, + () => props.placeholder, + () => invertEnterBehaviorRef.current, + () => onSubmitRef.current?.(), + completionCompartment, + props.emojiFrequencies, + (shortcode) => onEmojiSelectRef.current?.(shortcode), + ), + }); + + viewRef.current = new EditorView({ + state, + parent: elementRef.current, + }); + props.onControllerChange?.({ + focus: () => viewRef.current?.contentDOM.focus({ preventScroll: true }), + hasFocus: () => viewRef.current?.hasFocus ?? false, + insertText: (text) => { + const editor = viewRef.current; + if (!editor) return; + editor.dispatch({ + ...editor.state.replaceSelection(text), + annotations: Transaction.userEvent.of("input.type"), + scrollIntoView: true, + }); + }, + }); + if (props.autoFocus) viewRef.current.focus(); + + return () => { + props.onControllerChange?.(null); + viewRef.current?.destroy(); + viewRef.current = undefined; + }; + // Run once to initialize/destroy the editor instance. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + const editor = viewRef.current; + if (!editor) return; + + const next = props.value; + const current = editor.state.doc.toString(); + + if (next === current) return; + + editor.dispatch({ + changes: { + from: 0, + to: current.length, + insert: next, + }, + annotations: [ + externalValueSync.of(true), + Transaction.addToHistory.of(false), + ], + filter: false, + }); + }, [props.value]); + + useEffect(() => { + const editor = viewRef.current; + const compartment = completionCompartmentRef.current; + if (!editor || !compartment) return; + + const wasActive = completionStatus(editor.state) === "active"; + editor.dispatch({ + effects: compartment.reconfigure( + createEmojiAutocomplete(props.emojiFrequencies, (shortcode) => + onEmojiSelectRef.current?.(shortcode), + ), + ), + }); + if (wasActive) startCompletion(editor); + }, [props.emojiFrequencies]); + + return ( +

    + ); +} + +/** + * Executes createEditorExtensions. + * @param onChange Parameter onChange. + * @param getPlaceholder Parameter getPlaceholder. + * @param getInvertEnterBehavior Parameter getInvertEnterBehavior. + * @param onSubmit Parameter onSubmit. + * @returns Extension[]. + */ +function createEditorExtensions( + onChange: (value: string) => void, + getPlaceholder: () => string | undefined, + getInvertEnterBehavior: () => boolean, + onSubmit: () => void, + completionCompartment: Compartment, + emojiFrequencies: Readonly> | undefined, + onEmojiSelect: (shortcode: string) => void, +): Extension[] { + const editorKeymap = [ + ...defaultKeymap, + ...historyKeymap, + indentWithTab, + ] as unknown as readonly KeyBinding[]; + + const customEnterKeymap = keymap.of([ + { + key: "Shift-Enter", + run: (view) => { + if (completionStatus(view.state) === "active") { + return acceptCompletion(view); + } + if (!getInvertEnterBehavior()) { + return false; + } + + onSubmit(); + return true; + }, + }, + { + key: "Enter", + run: (view) => { + if (completionStatus(view.state) === "active") { + return acceptCompletion(view); + } + if (getInvertEnterBehavior()) { + return false; + } + + onSubmit(); + return true; + }, + }, + ]); + const completionTabKeymap = keymap.of([ + { + key: "Tab", + run: (view) => + completionStatus(view.state) === "active" + ? acceptCompletion(view) + : false, + }, + ]); + const emojiDeletionKeymap = keymap.of([ + { + key: "Backspace", + run: (view) => deleteEmoji(view, "backward"), + }, + { + key: "Delete", + run: (view) => deleteEmoji(view, "forward"), + }, + ]); + + return [ + history(), + markdown(), + completionCompartment.of( + createEmojiAutocomplete(emojiFrequencies, onEmojiSelect), + ), + emojiDecorations, + keymap.of(editorKeymap), + Prec.highest(completionTabKeymap), + Prec.highest(emojiDeletionKeymap), + Prec.highest(customEnterKeymap), + EditorView.lineWrapping, + placeholder(getPlaceholder() ?? ""), + EditorView.updateListener.of((update: ViewUpdate) => { + if (!update.docChanged) return; + if ( + update.transactions.some( + (transaction) => transaction.annotation(externalValueSync) === true, + ) + ) { + return; + } + onChange(update.state.doc.toString()); + }), + EditorView.theme({ + "&": { + fontSize: "inherit", + }, + "&.cm-editor": { + width: "100%", + }, + }), + EditorView.editorAttributes.of({ + class: "tm-md-editor", + spellcheck: "true", + "aria-label": "Markdown input", + }), + markdownDecorations, + ]; +} + +function createEmojiAutocomplete( + frequencies: Readonly> | undefined, + onEmojiSelect: (shortcode: string) => void, +) { + return autocompletion({ + activateOnTyping: true, + addToOptions: [ + { + position: 20, + render(completion) { + const container = document.createElement("span"); + createRoot(container).render( + , + ); + return container; + }, + }, + ], + maxRenderedOptions: MAX_RENDERED_EMOJI_OPTIONS, + override: [createEmojiCompletionSource(frequencies, onEmojiSelect)], + }); +} + +function normalizedFrequencies( + frequencies: Readonly> | undefined, +) { + const normalized = new Map(); + for (const [value, frequency] of Object.entries(frequencies ?? {})) { + const shortcode = resolveEmoji(value)?.shortcode; + if (!shortcode || !Number.isFinite(frequency) || frequency <= 0) continue; + normalized.set(shortcode, (normalized.get(shortcode) ?? 0) + frequency); + } + return normalized; +} + +export function createEmojiCompletionSource( + frequencies?: Readonly>, + onEmojiSelect: (shortcode: string) => void = () => undefined, +) { + const normalized = normalizedFrequencies(frequencies); + const maxFrequency = Math.max(0, ...normalized.values()); + + return (context: CompletionContext): CompletionResult | null => { + const token = context.matchBefore(/:[a-z0-9_+-]*$/i); + if (!token) return null; + if ( + codeRanges(context.state).some( + (range) => token.from < range.to && token.to > range.from, + ) + ) { + return null; + } + + const characterBefore = context.state.sliceDoc( + Math.max(0, token.from - 1), + token.from, + ); + if (characterBefore && /[a-z0-9_]/i.test(characterBefore)) return null; + + const query = token.text.slice(1).toLowerCase(); + const options: Completion[] = searchEmojis(query) + .map((emoji) => { + const aliases = emoji.aliases.map((alias) => alias.toLowerCase()); + const matchedAlias = + aliases.find((alias) => alias === query) ?? + aliases.find((alias) => alias.startsWith(query)) ?? + aliases.find((alias) => alias.includes(query)) ?? + emoji.name; + const relevance = !query + ? 0 + : matchedAlias === query + ? 80 + : matchedAlias.startsWith(query) + ? 40 + : 0; + const frequency = normalized.get(emoji.shortcode) ?? 0; + const usage = + maxFrequency > 0 + ? (15 * Math.log1p(frequency)) / Math.log1p(maxFrequency) + : 0; + + return { + apply(view, completion, from, to) { + view.dispatch({ + annotations: pickedCompletion.of(completion), + changes: { from, insert: `${emoji.shortcode} `, to }, + selection: EditorSelection.cursor( + from + emoji.shortcode.length + 1, + ), + }); + onEmojiSelect(emoji.shortcode); + }, + boost: relevance + usage, + displayLabel: emoji.shortcode, + label: `:${matchedAlias}:`, + type: "text", + frequency, + relevance, + } satisfies Completion & { frequency: number; relevance: number }; + }) + .sort( + (a, b) => + b.relevance - a.relevance || + b.frequency - a.frequency || + (a.displayLabel ?? a.label).localeCompare(b.displayLabel ?? b.label), + ); + + return { + from: token.from, + options, + validFor: /^:[a-z0-9_+-]*$/i, + }; + }; +} + +export const emojiCompletionSource = createEmojiCompletionSource(); + +/** + * Executes buildDecorations. + * @param view Parameter view. + * @returns DecorationSet. + */ +function buildDecorations(view: EditorView): DecorationSet { + const builder: Range[] = []; + const selections = view.state.selection.ranges.map( + (range: SelectionRange) => ({ + from: range.from, + to: range.to, + }), + ); + + let codeFenceOpen = false; + + for ( + let lineNumber = 1; + lineNumber <= view.state.doc.lines; + lineNumber += 1 + ) { + const line = view.state.doc.line(lineNumber); + const text = line.text; + const lineFrom = line.from; + const trimmed = text.trim(); + + const fence = text.match(/^```\s*([^`]*)$/); + if (fence) { + const ticksStart = lineFrom + text.indexOf("```"); + const ticksEnd = ticksStart + 3; + addHiddenToken(builder, selections, { from: ticksStart, to: ticksEnd }); + if (trimmed.length > 3) { + addHiddenToken(builder, selections, { + from: ticksEnd, + to: line.to, + }); + } + codeFenceOpen = !codeFenceOpen; + continue; + } + + if (codeFenceOpen) { + builder.push(codeLineDecoration.range(lineFrom)); + continue; + } + + const heading = text.match(/^(#{1,6})\s+/); + if (heading) { + const markerLength = heading[0].length; + addHiddenToken(builder, selections, { + from: lineFrom, + to: lineFrom + markerLength, + }); + + const level = heading[1].length; + const headingClass = Decoration.mark({ + class: `tm-md-heading tm-md-h${String(level)}`, + }); + const contentFrom = lineFrom + markerLength; + if (contentFrom < line.to) { + builder.push(headingClass.range(contentFrom, line.to)); + } + } + + const quote = text.match(/^>\s?/); + if (quote) { + addHiddenToken(builder, selections, { + from: lineFrom, + to: lineFrom + quote[0].length, + }); + } + + const unordered = text.match(/^(\s*)([-+*])\s+(?:\[( |x|X)\]\s+)?/); + if (unordered) { + const markerStart = lineFrom + unordered[1].length; + const markerEnd = markerStart + unordered[2].length + 1; + addHiddenToken(builder, selections, { from: markerStart, to: markerEnd }); + + const checkbox = unordered[0].match(/\[( |x|X)\]\s+$/); + if (checkbox) { + const checkboxStart = lineFrom + unordered[0].lastIndexOf("["); + addHiddenToken(builder, selections, { + from: checkboxStart, + to: checkboxStart + checkbox[0].length, + }); + } + } + + const ordered = text.match(/^(\s*)(\d+\.)\s+/); + if (ordered) { + const markerStart = lineFrom + ordered[1].length; + addHiddenToken(builder, selections, { + from: markerStart, + to: markerStart + ordered[2].length + 1, + }); + } + + if (/^(?:\*\s*){3,}$|^(?:-\s*){3,}$|^(?:_\s*){3,}$/.test(trimmed)) { + if (lineFrom < line.to) { + builder.push( + Decoration.mark({ class: "tm-md-hr" }).range(lineFrom, line.to), + ); + } + continue; + } + + const tableSeparator = /^\|?\s*:?-{3,}:?\s*(?:\|\s*:?-{3,}:?\s*)+\|?$/.test( + text, + ); + if (tableSeparator) { + if (lineFrom < line.to) { + builder.push( + Decoration.mark({ class: "tm-md-del" }).range(lineFrom, line.to), + ); + } + continue; + } + + const { styleRanges, tokenRanges } = collectInlineRanges(text, lineFrom); + + for (const range of styleRanges) { + if (range.from >= range.to) continue; + + if (range.className === "tm-md-strong") { + builder.push(strongDecoration.range(range.from, range.to)); + } else if (range.className === "tm-md-em") { + builder.push(emDecoration.range(range.from, range.to)); + } else if (range.className === "tm-md-del") { + builder.push(delDecoration.range(range.from, range.to)); + } else if (range.className === "tm-md-code") { + builder.push(codeDecoration.range(range.from, range.to)); + } else if (range.className === "tm-md-link") { + builder.push(linkDecoration.range(range.from, range.to)); + } + } + + for (const token of tokenRanges) { + addHiddenToken(builder, selections, token); + } + } + + return Decoration.set(builder, true); +} + +/** + * Keeps markdown syntax visible only when user selection intersects the token. + * This preserves cursor predictability and cross-token selection while still hiding syntax during reading. + */ +function addHiddenToken( + builder: Range[], + selections: ReadonlyArray<{ from: number; to: number }>, + token: { + from: number; + to: number; + }, +): void { + if (token.from >= token.to) return; + + const overlapsSelection = selections.some((selection) => { + const selectionFrom = Math.min(selection.from, selection.to); + const selectionTo = Math.max(selection.from, selection.to); + + if (selectionFrom === selectionTo) { + return selectionFrom >= token.from && selectionFrom <= token.to; + } + + return selectionFrom < token.to && selectionTo > token.from; + }); + + if (overlapsSelection) return; + builder.push(hiddenTokenDecoration.range(token.from, token.to)); +} diff --git a/packages/markdown/src/markdown.tsx b/packages/markdown/src/markdown.tsx new file mode 100644 index 0000000..cd2a210 --- /dev/null +++ b/packages/markdown/src/markdown.tsx @@ -0,0 +1,815 @@ +import { + Fragment, + useEffect, + useRef, + useState, + type ReactElement, + type ReactNode, +} from "react"; +import Emoji from "./emoji"; +import { findEmojiShortcodes } from "./emojiData"; +import { Check } from "lucide-react"; + +type InlineNode = + | { type: "text"; value: string } + | { type: "emoji"; shortcode: string } + | { type: "strong"; value: string } + | { type: "em"; value: string } + | { type: "del"; value: string } + | { type: "code"; value: string } + | { type: "link"; label: string; href: string } + | { type: "image"; alt: string; src: string }; + +type InlineDecorationRange = { + from: number; + to: number; + className: string; +}; + +type InlineTokenRange = { + from: number; + to: number; +}; + +type ListItem = { + text: string; + checked: boolean | null; +}; + +type TableBlock = { + type: "table"; + headers: string[]; + rows: string[][]; +}; + +type MarkdownBlock = + | { + type: "paragraph"; + text: string; + } + | { + type: "heading"; + level: number; + text: string; + } + | { + type: "hr"; + } + | { + type: "blockquote"; + text: string; + } + | { + type: "code"; + language: string; + code: string; + } + | { + type: "list"; + ordered: boolean; + items: ListItem[]; + } + | TableBlock; + +const INLINE_TOKEN_REGEX = + /!\[([^\]]*)\]\(([^)\s]+(?:\s+"[^"]*")?)\)|\[([^\]]+)\]\(([^)\s]+(?:\s+"[^"]*")?)\)|`([^`\n]+)`|~~([^~\n]+)~~|\*\*([^*\n]+)\*\*|__([^_\n]+)__|\*([^*\n]+)\*|(? + + + ); +} + +function CopyableCode({ + block = false, + language, + value, +}: { + block?: boolean; + language?: string; + value: string; +}) { + const [copied, setCopied] = useState(false); + const copiedTimer = useRef | undefined>( + undefined, + ); + + useEffect( + () => () => { + clearTimeout(copiedTimer.current); + }, + [], + ); + + async function copy() { + await navigator.clipboard.writeText(value); + setCopied(true); + clearTimeout(copiedTimer.current); + copiedTimer.current = setTimeout(() => setCopied(false), 1200); + } + + const code = ( + void copy()} + onKeyDown={(event) => { + if (event.key !== "Enter" && event.key !== " ") return; + event.preventDefault(); + void copy(); + }} + > + {value} + + ); + + if (block) { + return ( +
    +
    {code}
    + +
    + ); + } + + return ( + <> + {code} + + + ); +} + +/** + * Executes parseInlineNodes. + * @param input Parameter input. + * @returns InlineNode[]. + */ +export function parseInlineNodes(input: string): InlineNode[] { + const nodes: InlineNode[] = []; + + let cursor = 0; + let match = INLINE_TOKEN_REGEX.exec(input); + + while (match) { + const index = match.index; + const raw = match[0]; + + if (index > cursor) { + nodes.push(...parseEmojiText(input.slice(cursor, index))); + } + + if (match[1] !== undefined && match[2] !== undefined) { + nodes.push({ type: "image", alt: match[1], src: normalizeUrl(match[2]) }); + } else if (match[3] !== undefined && match[4] !== undefined) { + nodes.push({ + type: "link", + label: match[3], + href: normalizeUrl(match[4]), + }); + } else if (match[5] !== undefined) { + nodes.push({ type: "code", value: match[5] }); + } else if (match[6] !== undefined) { + nodes.push({ type: "del", value: match[6] }); + } else if (match[7] !== undefined || match[8] !== undefined) { + nodes.push({ type: "strong", value: match[7] ?? match[8] ?? "" }); + } else if (match[9] !== undefined || match[10] !== undefined) { + nodes.push({ type: "em", value: match[9] ?? match[10] ?? "" }); + } else { + nodes.push(...parseEmojiText(raw)); + } + + cursor = index + raw.length; + match = INLINE_TOKEN_REGEX.exec(input); + } + + if (cursor < input.length) { + nodes.push(...parseEmojiText(input.slice(cursor))); + } + + INLINE_TOKEN_REGEX.lastIndex = 0; + return nodes; +} + +export function parseEmojiText(input: string): InlineNode[] { + const nodes: InlineNode[] = []; + let cursor = 0; + + for (const match of findEmojiShortcodes(input)) { + if (match.from > cursor) { + nodes.push({ type: "text", value: input.slice(cursor, match.from) }); + } + + nodes.push({ type: "emoji", shortcode: match.emoji.shortcode }); + cursor = match.to; + } + + if (cursor < input.length) { + nodes.push({ type: "text", value: input.slice(cursor) }); + } + + return nodes; +} + +/** + * Executes collectInlineRanges. + * @param input Parameter input. + * @param offset Parameter offset. + * @returns { + styleRanges: InlineDecorationRange[]; + tokenRanges: InlineTokenRange[]; +}. + */ +export function collectInlineRanges( + input: string, + offset = 0, +): { + styleRanges: InlineDecorationRange[]; + tokenRanges: InlineTokenRange[]; +} { + const styleRanges: InlineDecorationRange[] = []; + const tokenRanges: InlineTokenRange[] = []; + + let match = INLINE_TOKEN_REGEX.exec(input); + + while (match) { + const raw = match[0]; + const start = offset + match.index; + const end = start + raw.length; + + if (match[1] !== undefined && match[2] !== undefined) { + const openLength = 2; + const closeLength = raw.endsWith(")") ? 1 : 0; + + const imageEnd = start + openLength + match[1].length; + tokenRanges.push({ from: start, to: start + openLength }); + tokenRanges.push({ from: imageEnd, to: imageEnd + 1 }); + + const srcStart = imageEnd + 1; + const srcEnd = end - closeLength; + tokenRanges.push({ from: srcStart, to: srcStart + 1 }); + tokenRanges.push({ from: srcEnd, to: srcEnd + closeLength }); + } else if (match[3] !== undefined && match[4] !== undefined) { + const label = match[3]; + const labelStart = start + 1; + const labelEnd = labelStart + label.length; + + tokenRanges.push({ from: start, to: start + 1 }); + tokenRanges.push({ from: labelEnd, to: labelEnd + 1 }); + tokenRanges.push({ from: labelEnd + 1, to: labelEnd + 2 }); + tokenRanges.push({ from: end - 1, to: end }); + + styleRanges.push({ + from: labelStart, + to: labelEnd, + className: "tm-md-link", + }); + } else if (match[5] !== undefined) { + const codeStart = start + 1; + const codeEnd = end - 1; + + tokenRanges.push({ from: start, to: start + 1 }); + tokenRanges.push({ from: end - 1, to: end }); + styleRanges.push({ + from: codeStart, + to: codeEnd, + className: "tm-md-code", + }); + } else if (match[6] !== undefined) { + const contentStart = start + 2; + const contentEnd = end - 2; + + tokenRanges.push({ from: start, to: start + 2 }); + tokenRanges.push({ from: end - 2, to: end }); + styleRanges.push({ + from: contentStart, + to: contentEnd, + className: "tm-md-del", + }); + } else if (match[7] !== undefined || match[8] !== undefined) { + const contentStart = start + 2; + const contentEnd = end - 2; + + tokenRanges.push({ from: start, to: start + 2 }); + tokenRanges.push({ from: end - 2, to: end }); + styleRanges.push({ + from: contentStart, + to: contentEnd, + className: "tm-md-strong", + }); + } else if (match[9] !== undefined || match[10] !== undefined) { + const contentStart = start + 1; + const contentEnd = end - 1; + + tokenRanges.push({ from: start, to: start + 1 }); + tokenRanges.push({ from: end - 1, to: end }); + styleRanges.push({ + from: contentStart, + to: contentEnd, + className: "tm-md-em", + }); + } + + match = INLINE_TOKEN_REGEX.exec(input); + } + + INLINE_TOKEN_REGEX.lastIndex = 0; + return { styleRanges, tokenRanges }; +} + +/** + * Executes parseMarkdownBlocks. + * @param markdown Parameter markdown. + * @returns MarkdownBlock[]. + */ +export function parseMarkdownBlocks(markdown: string): MarkdownBlock[] { + const lines = markdown.replace(/\r\n/g, "\n").split("\n"); + const blocks: MarkdownBlock[] = []; + + let index = 0; + + while (index < lines.length) { + const line = lines[index]; + + if (!line.trim()) { + index += 1; + continue; + } + + const codeFence = line.match(/^```\s*([^`]*)$/); + if (codeFence) { + const language = (codeFence[1] ?? "").trim(); + const codeLines: string[] = []; + index += 1; + + while (index < lines.length && !/^```\s*$/.test(lines[index])) { + codeLines.push(lines[index]); + index += 1; + } + + if (index < lines.length) { + index += 1; + } + + blocks.push({ type: "code", language, code: codeLines.join("\n") }); + continue; + } + + if (/^(?:\*\s*){3,}$|^(?:-\s*){3,}$|^(?:_\s*){3,}$/.test(line.trim())) { + blocks.push({ type: "hr" }); + index += 1; + continue; + } + + const heading = line.match(/^(#{1,6})\s+(.+)$/); + if (heading) { + blocks.push({ + type: "heading", + level: heading[1].length, + text: heading[2], + }); + index += 1; + continue; + } + + const quote = line.match(/^>\s?(.*)$/); + if (quote) { + const quoteLines: string[] = [quote[1]]; + index += 1; + + while (index < lines.length) { + const next = lines[index].match(/^>\s?(.*)$/); + if (!next) break; + quoteLines.push(next[1]); + index += 1; + } + + blocks.push({ type: "blockquote", text: quoteLines.join("\n") }); + continue; + } + + const tableCandidate = readTable(lines, index); + if (tableCandidate) { + blocks.push(tableCandidate.block); + index = tableCandidate.nextIndex; + continue; + } + + const unordered = line.match(/^\s*[-*+]\s+(.*)$/); + const ordered = line.match(/^\s*\d+\.\s+(.*)$/); + if (unordered || ordered) { + const orderedList = Boolean(ordered); + const items: ListItem[] = []; + + while (index < lines.length) { + const current = lines[index]; + const match = orderedList + ? current.match(/^\s*\d+\.\s+(.*)$/) + : current.match(/^\s*[-*+]\s+(.*)$/); + + if (!match) break; + + const task = match[1].match(/^\[( |x|X)\]\s+(.*)$/); + if (task) { + items.push({ + text: task[2], + checked: task[1].toLowerCase() === "x", + }); + } else { + items.push({ text: match[1], checked: null }); + } + + index += 1; + } + + blocks.push({ type: "list", ordered: orderedList, items }); + continue; + } + + const paragraphLines = [line]; + index += 1; + + while ( + index < lines.length && + lines[index].trim() && + !/^(#{1,6})\s+/.test(lines[index]) && + !/^```\s*/.test(lines[index]) && + !/^>\s?/.test(lines[index]) && + !/^\s*[-*+]\s+/.test(lines[index]) && + !/^\s*\d+\.\s+/.test(lines[index]) && + !/^(?:\*\s*){3,}$|^(?:-\s*){3,}$|^(?:_\s*){3,}$/.test(lines[index].trim()) + ) { + paragraphLines.push(lines[index]); + index += 1; + } + + blocks.push({ type: "paragraph", text: paragraphLines.join("\n") }); + } + + return blocks; +} + +/** + * Executes renderInline. + * @param nodes Parameter nodes. + * @returns React.ReactNode[]. + */ +function renderInline(nodes: InlineNode[]): ReactNode[] { + return nodes.map((node, index) => { + if (node.type === "text") { + return node.value; + } + + if (node.type === "emoji") { + return ( + + ); + } + + if (node.type === "strong") { + return ( + + {renderInline(parseEmojiText(node.value))} + + ); + } + + if (node.type === "em") { + return ( + + {renderInline(parseEmojiText(node.value))} + + ); + } + + if (node.type === "del") { + return ( + + {renderInline(parseEmojiText(node.value))} + + ); + } + + if (node.type === "code") { + return ; + } + + if (node.type === "link") { + return ( +
    + {renderInline(parseEmojiText(node.label))} + + ); + } + + return ( + {node.alt} + ); + }); +} + +/** + * Executes renderBlocks. + * @param blocks Parameter blocks. + * @returns React.ReactElement. + */ +export function renderBlocks(blocks: MarkdownBlock[]): ReactElement { + return ( + <> + {blocks.map((block, blockIndex) => { + if (block.type === "heading") { + const className = `tm-md-heading tm-md-h${String(block.level)}`; + if (block.level === 1) + return ( +

    + {renderInline(parseInlineNodes(block.text))} +

    + ); + if (block.level === 2) + return ( +

    + {renderInline(parseInlineNodes(block.text))} +

    + ); + if (block.level === 3) + return ( +

    + {renderInline(parseInlineNodes(block.text))} +

    + ); + if (block.level === 4) + return ( +

    + {renderInline(parseInlineNodes(block.text))} +

    + ); + if (block.level === 5) + return ( +
    + {renderInline(parseInlineNodes(block.text))} +
    + ); + return ( +
    + {renderInline(parseInlineNodes(block.text))} +
    + ); + } + + if (block.type === "blockquote") { + return ( +
    + {block.text.split("\n").map((line, lineIndex) => ( +

    {renderInline(parseInlineNodes(line))}

    + ))} +
    + ); + } + + if (block.type === "code") { + return ( + + ); + } + + if (block.type === "list") { + const Tag = block.ordered ? "ol" : "ul"; + return ( + + {block.items.map((item, itemIndex) => ( +
  • + {item.checked !== null ? ( + + ) : null} + {renderInline(parseInlineNodes(item.text))} +
  • + ))} +
    + ); + } + + if (block.type === "table") { + return ( +
    + + + + {block.headers.map((header, headerIndex) => ( + + ))} + + + + {block.rows.map((row, rowIndex) => ( + + {row.map((cell, cellIndex) => ( + + ))} + + ))} + +
    + {renderInline(parseInlineNodes(header))} +
    + {renderInline(parseInlineNodes(cell))} +
    +
    + ); + } + + if (block.type === "hr") { + return
    ; + } + + return ( +

    + {block.text.split("\n").map((line, lineIndex) => ( + + {lineIndex > 0 ?
    : null} + {renderInline(parseInlineNodes(line))} +
    + ))} +

    + ); + })} + + ); +} + +/** + * Executes normalizeUrl. + * @param input Parameter input. + * @returns string. + */ +function normalizeUrl(input: string): string { + const value = input.trim(); + if (/^(https?:|mailto:|tel:|\/)/i.test(value)) { + return value; + } + + return "#"; +} + +/** + * Executes splitTableRow. + * @param row Parameter row. + * @returns string[]. + */ +function splitTableRow(row: string): string[] { + const cleaned = row.trim().replace(/^\|/, "").replace(/\|$/, ""); + return cleaned.split("|").map((cell) => cell.trim()); +} + +/** + * Executes readTable. + * @param lines Parameter lines. + * @param index Parameter index. + * @returns { block: TableBlock; nextIndex: number } | null. + */ +function readTable( + lines: string[], + index: number, +): { block: TableBlock; nextIndex: number } | null { + const header = lines[index] ?? ""; + const separator = lines[index + 1] ?? ""; + + if (!header.includes("|") || !separator.includes("|")) { + return null; + } + + const separatorCells = splitTableRow(separator); + const isSeparator = separatorCells.every((cell) => /^:?-{3,}:?$/.test(cell)); + if (!isSeparator) { + return null; + } + + const headers = splitTableRow(header); + const rows: string[][] = []; + let cursor = index + 2; + + while (cursor < lines.length && lines[cursor].includes("|")) { + rows.push(splitTableRow(lines[cursor])); + cursor += 1; + } + + return { + block: { type: "table", headers, rows }, + nextIndex: cursor, + }; +} + +const markdownStyles = ` +.tm-md-root { color: var(--foreground); line-height: 1.65; font-size: 1rem; } +.tm-md-heading { margin: 0.2rem 0 0.35rem; font-weight: 700; line-height: 1.25; } +.tm-md-h1 { font-size: 1.65rem; } +.tm-md-h2 { font-size: 1.45rem; } +.tm-md-h3 { font-size: 1.25rem; } +.tm-md-h4 { font-size: 1.1rem; } +.tm-md-h5 { font-size: 1rem; } +.tm-md-h6 { font-size: 0.95rem; opacity: 0.9; } +.tm-md-blockquote { margin: 0.45rem 0; padding-left: 0.75rem; opacity: 0.95; } +.tm-md-blockquote p { margin: 0.2rem 0; } +.tm-md-pre { margin: 0.45rem 0; padding: 0.65rem 0.75rem; border-radius: 0.5rem; background: var(--muted); overflow-x: auto; } +.tm-md-code, .tm-md-codeblock { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 0.87em; cursor: pointer; } +.tm-md-code { padding: 0.08rem 0.32rem; border: 1px solid var(--border); border-radius: 0.28rem; background: var(--muted); } +.tm-md-codeblock { display: block; } +.tm-md-code:focus-visible, .tm-md-codeblock:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; } +.tm-md-strong { font-weight: 700; } +.tm-md-em { font-style: italic; } +.tm-md-del { text-decoration: line-through; } +.tm-md-link { color: var(--primary); text-decoration: underline; text-underline-offset: 0.14rem; } +.tm-md-image { display: block; max-width: 100%; border-radius: 0.4rem; margin: 0.5rem 0; } +.tm-md-emoji { display: inline-block; width: 1.15em; height: 1.15em; vertical-align: -0.18em; } +.tm-md-ul, .tm-md-ol { margin: 0.3rem 0 0.35rem 1.2rem; padding: 0; } +.tm-md-li { margin: 0.2rem 0; } +.tm-md-checkbox { margin-right: 0.5rem; vertical-align: middle; } +.tm-md-table-wrap { overflow-x: auto; margin: 0.45rem 0; } +.tm-md-table { border-collapse: collapse; width: 100%; min-width: 16rem; } +.tm-md-table th, .tm-md-table td { padding: 0.4rem 0.5rem; text-align: left; } +.tm-md-table th { background: var(--muted); font-weight: 600; } +.tm-md-hr { margin: 0.55rem 0; } + +.cm-editor.tm-md-editor { border-radius: inherit; background: transparent; caret-color: var(--foreground); } +.cm-editor.tm-md-editor.cm-focused { outline: none; box-shadow: none; } +.cm-editor.tm-md-editor .cm-scroller { font-family: inherit; line-height: 1.55; max-height: 30vh; overflow-y: auto; overflow-x: hidden; } +.cm-editor.tm-md-editor .cm-content { caret-color: var(--foreground); } +.cm-editor.tm-md-editor .cm-content { padding: var(--tm-md-content-padding, 0.25rem 0.625rem); min-height: 2rem; } +.cm-editor.tm-md-editor .cm-line { padding: 0; color: var(--foreground); } +.cm-editor.tm-md-editor .tm-md-editor-emoji { display: inline-block; width: 1.15em; height: 1.15em; vertical-align: -0.18em; object-fit: contain; pointer-events: none; } +.cm-editor.tm-md-editor .tm-md-hidden-token { color: transparent; opacity: 0; font-size: inherit; } +.cm-editor.tm-md-editor .tm-md-code-line { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; background: var(--muted); border-radius: 0.3rem; } +.cm-tooltip.cm-tooltip-autocomplete { min-width: 18rem; max-width: min(26rem, calc(100vw - 1rem)); overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius); background: var(--popover); color: var(--popover-foreground); box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); font-family: "Public Sans Variable", sans-serif; font-size: 0.875rem; } +.cm-editor.tm-md-editor .cm-tooltip.cm-tooltip-autocomplete > ul { max-height: min(20rem, 45vh); padding: 0.25rem; font-family: "Public Sans Variable", sans-serif; scrollbar-width: thin; scrollbar-color: var(--border) transparent; } +.cm-tooltip.cm-tooltip-autocomplete > ul::-webkit-scrollbar { width: 6px; height: 6px; } +.cm-tooltip.cm-tooltip-autocomplete > ul::-webkit-scrollbar-track { background: transparent; } +.cm-tooltip.cm-tooltip-autocomplete > ul::-webkit-scrollbar-thumb { border-radius: 9999px; background: var(--border); } +.cm-tooltip.cm-tooltip-autocomplete > ul > li { display: flex; min-height: 2.25rem; align-items: center; border-radius: calc(var(--radius) * 0.8); padding: 0.3rem 0.5rem; color: var(--popover-foreground); } +.cm-tooltip.cm-tooltip-autocomplete > ul > li:hover, +.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] { background: var(--accent); color: var(--accent-foreground); } +.cm-tooltip.cm-tooltip-autocomplete .cm-completionIcon { display: none; } +.cm-tooltip.cm-tooltip-autocomplete .cm-completionLabel { overflow: hidden; text-overflow: ellipsis; } +.cm-tooltip.cm-tooltip-autocomplete .cm-completionMatchedText { color: inherit; text-decoration: none; font-weight: 600; } +.cm-tooltip-autocomplete .tm-md-completion-emoji { display: inline-block; width: 1.35rem; height: 1.35rem; flex: 0 0 auto; margin-right: 0.5rem; vertical-align: middle; } +`; + +/** + * Executes ensureMarkdownStyles. + * @param none This function has no parameters. + * @returns void. + */ +export function ensureMarkdownStyles(): void { + if (typeof document === "undefined") return; + + const styleId = "tensamin-markdown-styles"; + let style = document.getElementById(styleId) as HTMLStyleElement | null; + + if (!style) { + style = document.createElement("style"); + style.id = styleId; + document.head.appendChild(style); + } + + if (style.textContent !== markdownStyles) { + style.textContent = markdownStyles; + } +} diff --git a/packages/markdown/src/text.tsx b/packages/markdown/src/text.tsx new file mode 100644 index 0000000..ca65fe0 --- /dev/null +++ b/packages/markdown/src/text.tsx @@ -0,0 +1,30 @@ +import { useMemo, type CSSProperties } from "react"; + +import { + ensureMarkdownStyles, + parseMarkdownBlocks, + renderBlocks, +} from "./markdown"; + +export type TextProps = { + value: string; + fontSize?: CSSProperties["fontSize"]; +}; + +/** + * Executes Text. + * @param props Parameter props. + * @returns unknown. + */ +export default function Text(props: TextProps) { + ensureMarkdownStyles(); + + const blocks = useMemo(() => parseMarkdownBlocks(props.value), [props.value]); + const renderedBlocks = useMemo(() => renderBlocks(blocks), [blocks]); + + return ( +
    + {renderedBlocks} +
    + ); +} diff --git a/packages/markdown/todo.md b/packages/markdown/todo.md new file mode 100644 index 0000000..b59da98 --- /dev/null +++ b/packages/markdown/todo.md @@ -0,0 +1 @@ +- Improve the Input box diff --git a/packages/markdown/tsconfig.json b/packages/markdown/tsconfig.json new file mode 100644 index 0000000..9714625 --- /dev/null +++ b/packages/markdown/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "strict": true, + "skipLibCheck": true, + "noEmit": true + }, + "include": ["src"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0cbdd6e..107149b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -459,6 +459,45 @@ importers: specifier: ^8.2.1 version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(yaml@2.9.0) + packages/markdown: + dependencies: + '@codemirror/autocomplete': + specifier: ^6.20.3 + version: 6.20.3 + '@codemirror/commands': + specifier: ^6.10.4 + version: 6.11.0 + '@codemirror/lang-markdown': + specifier: ^6.5.2 + version: 6.5.2 + '@codemirror/language': + specifier: ^6.12.4 + version: 6.12.4 + '@codemirror/state': + specifier: ^6.7.1 + version: 6.7.1 + '@codemirror/view': + specifier: ^6.43.8 + version: 6.43.9 + '@methanium/ui': + specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz + version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) + '@twemoji/api': + specifier: ^17.0.3 + version: 17.0.3 + emojibase-data: + specifier: ^17.0.0 + version: 17.0.0(emojibase@17.0.0) + lucide-react: + specifier: ^1.30.0 + version: 1.32.0(react@19.2.8) + react: + specifier: ^19.2.8 + version: 19.2.8 + react-dom: + specifier: ^19.2.8 + version: 19.2.8(react@19.2.8) + packages/mtp: dependencies: '@methanium/ui': @@ -2540,6 +2579,12 @@ packages: '@ts-morph/common@0.27.0': resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} + '@twemoji/api@17.0.3': + resolution: {integrity: sha512-iwERjxY0QgPGVwT6b1OKG0Oa9nIfHhJw+Ij1TapTBMKTvVCU6qdXPXX/XKwxKx5QZIJW5GwELUCtw8wlaIQ2ug==} + + '@twemoji/parser@17.0.2': + resolution: {integrity: sha512-X/P7pHsGOxnrupQYUVetIeuxBGgffFu8CLwoPMMjH9CWmQvlXiCpbTW/BXxMOCWXQojgHdmgdvm6IsCqAQ5nxA==} + '@types/cacheable-request@6.0.3': resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} @@ -4528,6 +4573,9 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonfile@5.0.0: + resolution: {integrity: sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==} + jsonfile@6.2.1: resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} @@ -8431,6 +8479,15 @@ snapshots: minimatch: 10.2.6 path-browserify: 1.0.1 + '@twemoji/api@17.0.3': + dependencies: + '@twemoji/parser': 17.0.2 + fs-extra: 8.1.0 + jsonfile: 5.0.0 + universalify: 0.1.2 + + '@twemoji/parser@17.0.2': {} + '@types/cacheable-request@6.0.3': dependencies: '@types/http-cache-semantics': 4.2.0 @@ -10619,6 +10676,12 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonfile@5.0.0: + dependencies: + universalify: 0.1.2 + optionalDependencies: + graceful-fs: 4.2.11 + jsonfile@6.2.1: dependencies: universalify: 2.0.1 From ede0199858d505be64126c6f03c681c0f71127f0 Mon Sep 17 00:00:00 2001 From: Alois Date: Tue, 25 Aug 2026 20:48:56 +0200 Subject: [PATCH 86/97] chore(mtp): udpate type maps --- mtp-type-maps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mtp-type-maps b/mtp-type-maps index a297dcc..6d97b5b 160000 --- a/mtp-type-maps +++ b/mtp-type-maps @@ -1 +1 @@ -Subproject commit a297dcce60bc6e84696c6a16f5fd510beb2ca643 +Subproject commit 6d97b5b9935b15d957444d38609378c66a24262a From 5056f084b41b74ffec84303d548a725a677edb67 Mon Sep 17 00:00:00 2001 From: Alois Date: Tue, 25 Aug 2026 20:58:32 +0200 Subject: [PATCH 87/97] chore(mtp): update type-maps --- mtp-type-maps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mtp-type-maps b/mtp-type-maps index 6d97b5b..e044182 160000 --- a/mtp-type-maps +++ b/mtp-type-maps @@ -1 +1 @@ -Subproject commit 6d97b5b9935b15d957444d38609378c66a24262a +Subproject commit e044182b895da4f220d266275eebeb0f264b1dbe From edcf0e15dd07a26d9e9635c5db77227baf4eb005 Mon Sep 17 00:00:00 2001 From: Alois Date: Tue, 25 Aug 2026 21:00:32 +0200 Subject: [PATCH 88/97] chore(mtp): update type-maps --- mtp-type-maps | 2 +- package.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mtp-type-maps b/mtp-type-maps index e044182..a70085b 160000 --- a/mtp-type-maps +++ b/mtp-type-maps @@ -1 +1 @@ -Subproject commit e044182b895da4f220d266275eebeb0f264b1dbe +Subproject commit a70085b0c41844745449c9913a361f5bb9bee529 diff --git a/package.json b/package.json index 051f699..1975028 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "start-adb:mobile": "cd apps/tauri && pnpm run start-adb:mobile", "dev:desktop": "cd apps/electron && pnpm run dev", "build:desktop": "cd apps/electron && pnpm run package", - "delete:mobile": "nix develop .#tauri --command node apps/tauri/scripts/delete-mobile.ts" + "delete:mobile": "nix develop .#tauri --command node apps/tauri/scripts/delete-mobile.ts", + "update-submodules": "git submodule update --remote --force --recursive" }, "devDependencies": { "@eslint/js": "^10.0.1", From 96b81d30b1408d3a94f1cf191eedbdc705f192b4 Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 27 Aug 2026 14:38:53 +0200 Subject: [PATCH 89/97] feat(pwa): keep service workers from getting registerd outside the pwa --- apps/pwa/src/runtime.tsx | 66 ++++++---------------------------------- apps/pwa/src/vite.ts | 1 + 2 files changed, 10 insertions(+), 57 deletions(-) diff --git a/apps/pwa/src/runtime.tsx b/apps/pwa/src/runtime.tsx index d7917cc..a1947eb 100644 --- a/apps/pwa/src/runtime.tsx +++ b/apps/pwa/src/runtime.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { toast } from "sonner"; import { setDatabaseEntry } from "@tensamin/shared/indexedDb"; @@ -6,11 +6,6 @@ import { isTauri } from "@tauri-apps/api/core"; import "./style.css"; -type BeforeInstallPromptEvent = Event & { - prompt: () => Promise; - userChoice: Promise<{ outcome: "accepted" | "dismissed" }>; -}; - const launchedFiles: File[] = []; const fileListeners = new Set<(file: File) => void>(); @@ -27,9 +22,10 @@ export function subscribeTuFileLaunch(listener: (file: File) => void) { }; } -function isStandalone() { +function isInstalledPwa() { return ( window.matchMedia("(display-mode: standalone)").matches || + window.matchMedia("(display-mode: window-controls-overlay)").matches || (navigator as Navigator & { standalone?: boolean }).standalone === true ); } @@ -65,13 +61,9 @@ async function enablePush() { await setDatabaseEntry("keys", "push-subscription", subscription.toJSON()); } -export default function PwaRuntime() { - const [installPrompt, setInstallPrompt] = - useState(null); - +function InstalledPwaRuntime() { useEffect(() => { if ( - isTauri() || !("serviceWorker" in navigator) || !["http:", "https:"].includes(window.location.protocol) ) { @@ -129,16 +121,6 @@ export default function PwaRuntime() { }; }, []); - useEffect(() => { - const handleInstallPrompt = (event: Event) => { - event.preventDefault(); - setInstallPrompt(event as BeforeInstallPromptEvent); - }; - window.addEventListener("beforeinstallprompt", handleInstallPrompt); - return () => - window.removeEventListener("beforeinstallprompt", handleInstallPrompt); - }, []); - useEffect(() => { const launchQueue = ( window as Window & { @@ -159,41 +141,7 @@ export default function PwaRuntime() { }, []); useEffect(() => { - if (!installPrompt) return; - toast("Install Tensamin for a native app experience", { - duration: Infinity, - action: { - label: "Install", - onClick: () => { - void installPrompt.prompt().then(() => installPrompt.userChoice); - setInstallPrompt(null); - }, - }, - }); - }, [installPrompt]); - - useEffect(() => { - const isAppleMobile = /iPad|iPhone|iPod/.test(navigator.userAgent); if ( - isTauri() || - !isAppleMobile || - isStandalone() || - localStorage.getItem("pwa-ios-install-hint") - ) { - return; - } - localStorage.setItem("pwa-ios-install-hint", "shown"); - toast( - "Install Tensamin from Safari's Share menu to enable background notifications.", - { - duration: 12_000, - }, - ); - }, []); - - useEffect(() => { - if ( - !isStandalone() || !("Notification" in window) || Notification.permission !== "default" || localStorage.getItem("pwa-push-hint") @@ -222,7 +170,6 @@ export default function PwaRuntime() { useEffect(() => { if ( - isStandalone() && "Notification" in window && Notification.permission === "granted" && import.meta.env.VITE_WEB_PUSH_PUBLIC_KEY @@ -235,3 +182,8 @@ export default function PwaRuntime() { return null; } + +export default function PwaRuntime() { + if (isTauri() || !isInstalledPwa()) return null; + return ; +} diff --git a/apps/pwa/src/vite.ts b/apps/pwa/src/vite.ts index 908a3d2..962dce1 100644 --- a/apps/pwa/src/vite.ts +++ b/apps/pwa/src/vite.ts @@ -128,6 +128,7 @@ export function tensaminPwa(): Plugin[] { filename: "serviceWorker.ts", injectRegister: null, registerType: "prompt", + buildBase: "/", manifestFilename: "manifest.json", includeAssets: ["favicon.ico", "icons/*.png"], manifest: { From 0fbedf6733710d08b5cedc28bd3e4043012198b0 Mon Sep 17 00:00:00 2001 From: forgejo-actions Date: Thu, 27 Aug 2026 12:59:08 +0000 Subject: [PATCH 90/97] (qol): update release flake hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index d91a817..e02a001 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.11"; - x86_64DebHash = "sha256-p/6boNv9uWTHsPTVa3EhGzr41EwRzCY/fJWlj854DVA="; + x86_64DebHash = "sha256-iMEgdjY8Ghlx6K/YzKC5JAZbeHNJDIFHm8MKmM4efaI="; forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { From 1d1b304bcf8e056de20360d08ff5be028e947778 Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 27 Aug 2026 19:32:48 +0200 Subject: [PATCH 91/97] feat(workflows): remove env thing --- .forgejo/workflows/dependency-builds.yml | 1 - .forgejo/workflows/deploy-dev.yml | 3 --- .forgejo/workflows/deploy-prod.yml | 3 --- 3 files changed, 7 deletions(-) diff --git a/.forgejo/workflows/dependency-builds.yml b/.forgejo/workflows/dependency-builds.yml index 709c75b..f8ec1cd 100644 --- a/.forgejo/workflows/dependency-builds.yml +++ b/.forgejo/workflows/dependency-builds.yml @@ -4,7 +4,6 @@ on: pull_request: env: - NIX_CONFIG: experimental-features = nix-command flakes FORGEJO_TOKEN: "" GITHUB_TOKEN: "" diff --git a/.forgejo/workflows/deploy-dev.yml b/.forgejo/workflows/deploy-dev.yml index 0d5be50..a09f69b 100644 --- a/.forgejo/workflows/deploy-dev.yml +++ b/.forgejo/workflows/deploy-dev.yml @@ -5,9 +5,6 @@ on: paths-ignore: - flake.nix -env: - NIX_CONFIG: experimental-features = nix-command flakes - jobs: build-web: runs-on: nixos diff --git a/.forgejo/workflows/deploy-prod.yml b/.forgejo/workflows/deploy-prod.yml index d85ce27..5fe2ba9 100644 --- a/.forgejo/workflows/deploy-prod.yml +++ b/.forgejo/workflows/deploy-prod.yml @@ -6,9 +6,6 @@ on: paths-ignore: - flake.nix -env: - NIX_CONFIG: experimental-features = nix-command flakes - jobs: build-web: runs-on: nixos From aa34bd962b6539289755f28e8cd7b938bd19f7e9 Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 27 Aug 2026 19:35:17 +0200 Subject: [PATCH 92/97] temp(mtp): temp commit stuff that needs to get a rework --- packages/mtp/package.json | 5 +- packages/mtp/src/context.test.tsx | 21 -- packages/mtp/src/context.tsx | 308 ++++++++++++------------------ pnpm-lock.yaml | 9 - 4 files changed, 124 insertions(+), 219 deletions(-) delete mode 100644 packages/mtp/src/context.test.tsx diff --git a/packages/mtp/package.json b/packages/mtp/package.json index 982593a..dfd973c 100644 --- a/packages/mtp/package.json +++ b/packages/mtp/package.json @@ -14,13 +14,10 @@ "dependencies": { "@methanium/ui": "*", "@tauri-apps/api": "^2.11.1", - "@tensamin/crypto": "workspace:*", "@tensamin/shared": "workspace:*", "@tensamin/storage": "workspace:*", "mtp": "*", - "react": "^19.2.8", - "react-dom": "^19.2.8", - "zod": "^4.4.3" + "react": "^19.2.8" }, "devDependencies": { "eslint": "^10.8.0" diff --git a/packages/mtp/src/context.test.tsx b/packages/mtp/src/context.test.tsx deleted file mode 100644 index 7f50aba..0000000 --- a/packages/mtp/src/context.test.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { isPushType, validateResponse } from "./context"; - -describe("MTP protocol dispatch", () => { - it("preserves protocol errors for the request layer", () => { - const error = validateResponse("GetStates", { - id: 12, - type: "ErrorInternal", - data: { ErrorType: "temporary" }, - }); - expect(error.type).toBe("ErrorInternal"); - expect(error.id).toBe(12); - }); - - it("recognizes initial and live presence pushes", () => { - expect(isPushType("GetStates")).toBe(true); - expect(isPushType("ClientChanged")).toBe(true); - expect(isPushType("UnknownMessage")).toBe(false); - }); -}); diff --git a/packages/mtp/src/context.tsx b/packages/mtp/src/context.tsx index af06ee0..288acbf 100644 --- a/packages/mtp/src/context.tsx +++ b/packages/mtp/src/context.tsx @@ -10,9 +10,18 @@ import { } from "react"; import { invoke, isTauri } from "@tauri-apps/api/core"; import { listen, type UnlistenFn } from "@tauri-apps/api/event"; -import { MTPClient } from "mtp"; -import { type z } from "zod"; -import { ConnectionState } from "mtp"; +import { + base64ToBytes, + ConnectionState, + MTPClient, + MTPProxyConnection, + type MTPFrame, + type MTPKeyMaterialInput, + type MTPProxyAdapter, + type MTPRequestOptions, + type MTPRequestFunction, + type MTPResponseFrame, +} from "mtp"; import createAsyncQueue from "@tensamin/shared/asyncQueue"; import { toast as sonnerToast } from "@methanium/ui"; @@ -24,35 +33,15 @@ import { type MTP as Schemas, } from "@tensamin/shared/data"; import { log } from "@tensamin/shared/log"; -import { ProtocolError } from "@tensamin/shared/errors"; import { useStorage } from "@tensamin/storage/context"; import { RECONNECT_RESET, RECONNECT_TRIES, RETRY_INTERVAL } from "./values"; -function base64ToUint8Array(b64: string) { - const bin = atob(b64); - const out = new Uint8Array(bin.length); - - for (let i = 0; i < bin.length; i++) { - out[i] = bin.charCodeAt(i); - } - - return out; -} - export type ProtocolMessage< T extends keyof Schemas & string = keyof Schemas & string, -> = { - id?: number; - type: T | string; - data: z.infer; -}; +> = MTPResponseFrame; -export type BoundSendFn = ( - type: T, - data?: z.infer, - options?: { id?: number }, -) => Promise>; +export type BoundSendFn = MTPRequestFunction; export type PushHandler = (message: ProtocolMessage) => void | Promise; @@ -68,6 +57,15 @@ const PUSH_TYPES = [ "ErrorNoIota", ] as const; +function encodedPublicKey(value: string): MTPKeyMaterialInput { + const trimmed = value.trim(); + const hex = trimmed.replace(/^0x/i, ""); + return { + value: /^[0-9a-f]+$/i.test(hex) ? hex : trimmed, + encoding: /^[0-9a-f]+$/i.test(hex) ? "hex" : "base64", + }; +} + export function isPushType(type: string): boolean { return (PUSH_TYPES as readonly string[]).includes(type); } @@ -114,53 +112,6 @@ type ContextType = { const MTPContext = createContext(undefined); -function getProtocolErrorDetails(error: unknown) { - if (typeof error !== "object" || error === null || !("type" in error)) { - return null; - } - - const protocolError = error as { - id?: unknown; - type?: unknown; - data?: unknown; - }; - return { - id: protocolError.id, - type: protocolError.type, - data: protocolError.data, - }; -} - -// Zod schema validation -export function validateResponse( - type: T, - message: { id?: number; type: string; data: unknown }, -): ProtocolMessage { - if (message.type.startsWith("Error")) { - return message as ProtocolMessage; - } - - const schema = - schemas[message.type as keyof Schemas & string]?.response ?? - schemas[type]?.response; - if (!schema) { - return message as ProtocolMessage; - } - - const parsed = schema.safeParse(message.data); - if (!parsed.success) { - throw new Error( - `Response validation failed for ${type}: ${parsed.error.message}`, - ); - } - - return { - id: message.id, - type: message.type, - data: parsed.data, - } as ProtocolMessage; -} - function useMessageHandlers() { const interceptorsRef = useRef(new Set()); const pushHandlersRef = useRef(new Set()); @@ -202,9 +153,7 @@ function BrowserProvider(props: { const [freshContacts, setFreshContacts] = useState([]); const [freshCalls, setFreshCalls] = useState([]); - const clientRef = useRef> | null>( - null, - ); + const clientRef = useRef | null>(null); const { addInterceptor, interceptorsRef, @@ -221,7 +170,6 @@ function BrowserProvider(props: { load("omega_url").then(setMtpUrl); }, [load]); - // Validation override functions const send: BoundSendFn = useMemo( () => async (type, data, options) => { const client = clientRef.current; @@ -230,24 +178,8 @@ function BrowserProvider(props: { throw new Error("mtp is not connected"); } - const message = await client.request( - type, - (data ?? {}) as Record, - options, - ); - const response = validateResponse(type, message); + const response = await client.request(type, data, options); setFreshContacts((contacts) => removeMissingContacts(contacts, response)); - if (response.type.startsWith("Error")) { - const errorData = response.data as Record; - throw new ProtocolError({ - type: response.type, - requestId: response.id, - errorType: - typeof errorData.ErrorType === "string" - ? errorData.ErrorType - : undefined, - }); - } return response; }, [], @@ -259,9 +191,7 @@ function BrowserProvider(props: { return () => {}; } - return client.subscribe(type, (message) => { - handler(validateResponse(type, message)); - }); + return client.subscribe(type, handler); }, []); // Reconnect stuff @@ -324,7 +254,7 @@ function BrowserProvider(props: { if (disposed || props.blockConnection) return; const generation = ++connectionGeneration; - let client: Awaited> | null = null; + let client: MTPClient | null = null; let failed = false; const cleanup = () => { client?.disconnect(); @@ -398,15 +328,20 @@ function BrowserProvider(props: { log(2, "mtp", "green", "Connecting to: " + url); - client = await MTPClient.create({ + client = await MTPClient.create({ url, credentials: { clientId: userId, - keyring: base64ToUint8Array(keyring), + keyring: base64ToBytes(keyring), }, - hostPublicKey: omikronPublicKey, + hostPublicKey: encodedPublicKey(omikronPublicKey), descriptor: "client", pings: true, + schemas, + throwProtocolErrors: true, + onValidationError: (error) => { + log(1, "mtp", "red", "Failed to validate MTP message", error); + }, logger: (event) => { if (event.type === "state") { if (generation !== connectionGeneration) return; @@ -458,16 +393,7 @@ function BrowserProvider(props: { clientRef.current = activeClient; for (const type of PUSH_TYPES) { activeClient.subscribe(type, (message) => { - let validated: ProtocolMessage; - try { - validated = validateResponse(type, message); - } catch (error) { - log(1, "mtp", "red", "Failed to validate push message", error, { - type, - data: message.data, - }); - return; - } + const validated = message as ProtocolMessage; setFreshContacts((contacts) => removeMissingContacts(contacts, validated), @@ -515,11 +441,7 @@ function BrowserProvider(props: { "ClientStateSync", (message) => { cleanupStateSync(); - try { - resolve(validateResponse("ClientStateSync", message)); - } catch (error) { - reject(error); - } + resolve(message); }, ); unsubscribeNoIota = activeClient.subscribe("ErrorNoIota", () => { @@ -539,15 +461,10 @@ function BrowserProvider(props: { ); } - const acknowledgement = await activeClient.request("ClientStateAck", { + await activeClient.request("ClientStateAck", { SessionId: finalResponse.data.SessionId, VersionNumber: finalResponse.data.VersionNumber, }); - if (acknowledgement.type.startsWith("Error")) { - throw new Error( - `State acknowledgement failed: ${acknowledgement.type}`, - ); - } if (disposed || clientRef.current !== activeClient) return; @@ -573,7 +490,7 @@ function BrowserProvider(props: { "mtp", "red", `Connection/authentication attempt failed: ${connectErrorMessage}`, - getProtocolErrorDetails(connectError) ?? connectError, + connectError, ); scheduleReconnect(connectError); @@ -694,6 +611,39 @@ type NativeSnapshot = { error?: string; }; +class TauriMTPAdapter implements MTPProxyAdapter { + readonly #subscriptions = new Map void>>(); + + async request( + type: string, + data: Record, + options?: MTPRequestOptions, + ) { + return await invoke("mtp_request", { + typeName: type, + data, + id: options?.id, + }); + } + + subscribe(type: string, handler: (message: MTPFrame) => void) { + const handlers = + this.#subscriptions.get(type) ?? new Set<(message: MTPFrame) => void>(); + handlers.add(handler); + this.#subscriptions.set(type, handlers); + return () => { + handlers.delete(handler); + if (handlers.size === 0) this.#subscriptions.delete(type); + }; + } + + dispatch(message: MTPFrame) { + for (const handler of this.#subscriptions.get(message.type) ?? []) { + handler(message); + } + } +} + function TauriProvider(props: { children: ReactNode; blockConnection?: boolean; @@ -714,8 +664,16 @@ function TauriProvider(props: { pushHandlersRef, subscribePush, } = useMessageHandlers(); - const subscriptionsRef = useRef( - new Map void>>(), + const [adapter] = useState(() => new TauriMTPAdapter()); + const [connection] = useState( + () => + new MTPProxyConnection(adapter, { + schemas, + throwProtocolErrors: true, + onValidationError: (error) => { + log(1, "mtp", "red", "Failed to validate native MTP message", error); + }, + }), ); const applySnapshot = useCallback((next: NativeSnapshot) => { @@ -739,39 +697,35 @@ function TauriProvider(props: { const dispatchMessage = useCallback( (raw: unknown) => { if (!raw || typeof raw !== "object" || !("type" in raw)) return; - const message = raw as { id?: number; type: string; data: unknown }; - let validated: ProtocolMessage; - try { - validated = validateResponse( - message.type as keyof Schemas & string, - message, - ); - } catch (error) { - log(1, "mtp", "red", "Failed to validate native MTP message", error); - return; - } - for (const handler of subscriptionsRef.current.get(validated.type) ?? - []) { - handler(validated); - } - if (!isPushType(validated.type)) return; - setFreshContacts((contacts) => - removeMissingContacts(contacts, validated), - ); - for (const handler of [...pushHandlersRef.current]) { - void Promise.resolve(handler(validated)).catch((error) => { - log(1, "mtp", "red", "Native MTP push handler failed", error, { - type: validated.type, - }); - }); - } - if (validated.type === "GetStates") { - lastInitialStateRef.current = validated; - } + adapter.dispatch(raw as MTPFrame); }, - [lastInitialStateRef, pushHandlersRef], + [adapter], ); + useEffect(() => { + const unsubscribers = PUSH_TYPES.map((type) => + connection.subscribe(type, (message) => { + const validated = message as ProtocolMessage; + setFreshContacts((contacts) => + removeMissingContacts(contacts, validated), + ); + for (const handler of [...pushHandlersRef.current]) { + void Promise.resolve(handler(validated)).catch((error) => { + log(1, "mtp", "red", "Native MTP push handler failed", error, { + type, + }); + }); + } + if (validated.type === "GetStates") { + lastInitialStateRef.current = validated; + } + }), + ); + return () => { + for (const unsubscribe of unsubscribers) unsubscribe(); + }; + }, [connection, lastInitialStateRef, pushHandlersRef]); + useEffect(() => { if (props.blockConnection) return; let disposed = false; @@ -847,26 +801,10 @@ function TauriProvider(props: { const send = useCallback( async (type, data, options) => { - const response = await invoke("mtp_request", { - typeName: type, - data: data ?? {}, - id: options?.id, - }); - const validated = validateResponse(type, response); + const validated = await connection.request(type, data, options); setFreshContacts((contacts) => removeMissingContacts(contacts, validated), ); - if (validated.type.startsWith("Error")) { - const errorData = validated.data as Record; - throw new ProtocolError({ - type: validated.type, - requestId: validated.id, - errorType: - typeof errorData.ErrorType === "string" - ? errorData.ErrorType - : undefined, - }); - } for (const interceptor of interceptorsRef.current) { void Promise.resolve( interceptor({ type, data, response: validated as ProtocolMessage }), @@ -876,20 +814,13 @@ function TauriProvider(props: { } return validated; }, - [interceptorsRef], + [connection, interceptorsRef], ); - const subscribe = useCallback((type, handler) => { - const handlers = - subscriptionsRef.current.get(type) ?? - new Set<(message: ProtocolMessage) => void>(); - handlers.add(handler as (message: ProtocolMessage) => void); - subscriptionsRef.current.set(type, handlers); - return () => { - handlers.delete(handler as (message: ProtocolMessage) => void); - if (handlers.size === 0) subscriptionsRef.current.delete(type); - }; - }, []); + const subscribe = useCallback( + (type, handler) => connection.subscribe(type, handler), + [connection], + ); const connected = snapshot.readyState === ConnectionState.Connected; const contextReady = connected && snapshot.identified; @@ -916,7 +847,7 @@ function TauriProvider(props: { ); } -export function Provider(props: { +function BrowserProviderLoader(props: { children: ReactNode; blockConnection?: boolean; }) { @@ -941,10 +872,17 @@ export function Provider(props: { if (wasmError) throw wasmError; if (!wasmReady) return null; + return ; +} + +export function Provider(props: { + children: ReactNode; + blockConnection?: boolean; +}) { return isTauri() ? ( ) : ( - + ); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index faff301..721102f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -458,9 +458,6 @@ importers: '@tauri-apps/api': specifier: ^2.11.1 version: 2.11.1 - '@tensamin/crypto': - specifier: workspace:* - version: link:../crypto '@tensamin/shared': specifier: workspace:* version: link:../shared @@ -473,12 +470,6 @@ importers: react: specifier: ^19.2.8 version: 19.2.8 - react-dom: - specifier: ^19.2.8 - version: 19.2.8(react@19.2.8) - zod: - specifier: ^4.4.3 - version: 4.4.3 devDependencies: eslint: specifier: ^10.8.0 From 0a304e44f2023807703e44fd4995b8840a3b9aaf Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 27 Aug 2026 23:30:33 +0200 Subject: [PATCH 93/97] feat(mtp): move useful stuff over to mtp directly --- .cargo/config.toml | 2 + apps/tauri/.cargo/config.toml | 2 - apps/tauri/src-tauri/src/mtp_backend.rs | 99 +- packages/cache/src/sync.tsx | 18 +- packages/call/src/store.tsx | 15 +- packages/chat/src/context.tsx | 160 +--- packages/markdown/src/markdown.tsx | 4 +- packages/mtp/package.json | 7 +- packages/mtp/src/browser.tsx | 529 +++++++++++ packages/mtp/src/context.test.tsx | 220 ----- packages/mtp/src/context.tsx | 1105 +---------------------- packages/mtp/src/index.ts | 4 +- packages/mtp/src/mtpContext.tsx | 159 ++++ packages/mtp/src/protocolFields.test.ts | 44 - packages/mtp/src/protocolFields.ts | 58 -- packages/mtp/src/requestIds.test.ts | 25 - packages/mtp/src/requestIds.ts | 24 - packages/mtp/src/tauri.tsx | 258 ++++++ packages/notifications/src/context.tsx | 251 +++-- packages/user/src/context.tsx | 58 +- pnpm-lock.yaml | 41 +- pnpm-workspace.yaml | 2 +- 22 files changed, 1216 insertions(+), 1869 deletions(-) create mode 100644 .cargo/config.toml delete mode 100644 apps/tauri/.cargo/config.toml create mode 100644 packages/mtp/src/browser.tsx delete mode 100644 packages/mtp/src/context.test.tsx create mode 100644 packages/mtp/src/mtpContext.tsx delete mode 100644 packages/mtp/src/protocolFields.test.ts delete mode 100644 packages/mtp/src/protocolFields.ts delete mode 100644 packages/mtp/src/requestIds.test.ts delete mode 100644 packages/mtp/src/requestIds.ts create mode 100644 packages/mtp/src/tauri.tsx diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..46adaad --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[env] +MTP_TYPE_MAPS = { value = "mtp-type-maps/type-maps.yaml", relative = true } diff --git a/apps/tauri/.cargo/config.toml b/apps/tauri/.cargo/config.toml deleted file mode 100644 index 161678f..0000000 --- a/apps/tauri/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[env] -MTP_TYPE_MAPS = { value = "../../mtp-type-maps/type-maps.yaml", relative = true } diff --git a/apps/tauri/src-tauri/src/mtp_backend.rs b/apps/tauri/src-tauri/src/mtp_backend.rs index 14365b8..fa28597 100644 --- a/apps/tauri/src-tauri/src/mtp_backend.rs +++ b/apps/tauri/src-tauri/src/mtp_backend.rs @@ -341,7 +341,7 @@ async fn supervise(generation: u64) { let notification_config = config.clone(); let notification_worker = tokio::spawn(async move { while let Some(frame) = notification_rx.recv().await { - if !manager().is_current(generation) { + if !manager.is_current(generation) { break; } if let Err(error) = notify_message( @@ -497,7 +497,7 @@ fn prepare_initial_state_ack( .ok_or("ClientStateSync payload is not an object")?; let session_id = required_integer(data, "SessionId")?; let version = required_integer(data, "VersionNumber")?; - let ack = CommunicationValue::new(CommunicationType::ClientStateAck) + let ack = CommunicationValue::new(communication_type("ClientStateAck")?) .with_id(request_ids.next()?) .add_typed_default(DataType::SessionId, number_to_data(session_id)) .add_typed_default(DataType::VersionNumber, number_to_data(version)); @@ -645,7 +645,7 @@ async fn await_initial_state( return Err("No Iota is currently connected".into()); } - if frame.is_type(CommunicationType::ClientStateSync) { + if frame.get_type_name() == Some("ClientStateSync") { return Ok((frame, buffered)); } @@ -740,7 +740,7 @@ async fn notify_message( let message = frame .get_data(DataType::Message) .ok_or("MessageLive omitted Message")?; - let content = container_value(message, DataType::AppContent) + let content = container_value_by_name(message, "Content") .and_then(DataValue::as_str) .ok_or("MessageLive omitted Content")?; let keyring_bytes = decode_browser_base64(&config.keyring)?; @@ -888,42 +888,24 @@ fn container_value(value: &DataValue, field: DataType) -> Option<&DataValue> { value.get_field(id) } -fn wire_field_name(name: &str) -> &str { - match name { - "Content" => "AppContent", - "CreatedAt" => "AppCreatedAt", - "MessageId" => "AppMessageId", - _ => name, - } +fn container_value_by_name<'a>(value: &'a DataValue, field: &str) -> Option<&'a DataValue> { + container_value(value, DataType::from_name(field)?) } -fn application_field_name(name: &str) -> &str { - match name { - "AppContent" => "Content", - "AppCreatedAt" => "CreatedAt", - "AppMessageId" => "MessageId", - _ => name, - } +fn communication_type(name: &str) -> Result { + CommunicationType::from_name(name).ok_or_else(|| format!("unknown communication type: {name}")) } fn json_to_frame(type_name: &str, data: Value, id: u32) -> Result { - let comm_type = CommunicationType::from_name(type_name) - .ok_or_else(|| format!("unknown communication type: {type_name}"))?; + let comm_type = communication_type(type_name)?; let mut frame = CommunicationValue::new(comm_type).with_id(id); let Value::Object(fields) = data else { return Err("MTP request data must be an object".into()); }; - let mut translated_fields = std::collections::HashSet::::with_capacity(fields.len()); for (name, value) in fields { - let wire_name = wire_field_name(&name).to_owned(); - if !translated_fields.insert(wire_name.clone()) { - return Err(format!( - "duplicate MTP field after translation: {wire_name}" - )); - } let data_type = - DataType::from_name(&wire_name).ok_or_else(|| format!("unknown data type: {name}"))?; - frame = frame.add_typed_default(data_type, json_to_data(&wire_name, value)?); + DataType::from_name(&name).ok_or_else(|| format!("unknown data type: {name}"))?; + frame = frame.add_typed_default(data_type, json_to_data(&name, value)?); } Ok(frame) } @@ -961,21 +943,13 @@ fn json_to_data(field: &str, value: Value) -> Result { ), Value::Object(fields) => { let mut entries = Vec::with_capacity(fields.len()); - let mut translated_fields = - std::collections::HashSet::::with_capacity(fields.len()); for (name, value) in fields { - let wire_name = wire_field_name(&name).to_owned(); - if !translated_fields.insert(wire_name.clone()) { - return Err(format!( - "duplicate MTP field after translation: {wire_name}" - )); - } - let data_type = DataType::from_name(&wire_name) + let data_type = DataType::from_name(&name) .ok_or_else(|| format!("unknown nested data type: {name}"))?; let id = data_type .try_to_id(&TypeMap::latest()) .ok_or_else(|| format!("unmapped data type: {name}"))?; - entries.push((id, json_to_data(&wire_name, value)?)); + entries.push((id, json_to_data(&name, value)?)); } DataValue::Container(entries) } @@ -1020,13 +994,7 @@ fn frame_data_to_json(frame: &CommunicationValue) -> Result { let name = map .data_type_name(id.0) .ok_or_else(|| format!("unknown data type id: {}", id.0))?; - let application_name = application_field_name(name); - if result.contains_key(application_name) { - return Err(format!( - "duplicate MTP field after translation: {application_name}" - )); - } - result.insert(application_name.to_owned(), data_to_json(value, &map)?); + result.insert(name.to_owned(), data_to_json(value, &map)?); } Ok(Value::Object(result)) } @@ -1057,13 +1025,7 @@ fn data_to_json(value: &DataValue, map: &TypeMap) -> Result { let name = map .data_type_name(id.0) .ok_or_else(|| format!("unknown nested data type id: {}", id.0))?; - let application_name = application_field_name(name); - if object.contains_key(application_name) { - return Err(format!( - "duplicate MTP field after translation: {application_name}" - )); - } - object.insert(application_name.to_owned(), data_to_json(value, map)?); + object.insert(name.to_owned(), data_to_json(value, map)?); } Value::Object(object) } @@ -1084,7 +1046,7 @@ mod tests { use serde_json::json; use super::{ - container_value, decode_browser_base64, decode_sdk_bytes, frame_to_json, + container_value_by_name, decode_browser_base64, decode_sdk_bytes, frame_to_json, jittered_retry_delay, json_to_frame, prepare_initial_state_ack, RequestIdAllocator, }; @@ -1117,7 +1079,7 @@ mod tests { } #[test] - fn json_content_uses_app_content_wire_type() { + fn json_content_uses_content_wire_type() { let frame = json_to_frame( "MessageEdit", json!({ @@ -1131,14 +1093,14 @@ mod tests { assert_eq!( frame - .get_data(DataType::AppContent) + .get_data(DataType::Content) .and_then(DataValue::as_str), Some("ciphertext") ); } #[test] - fn nested_json_content_uses_app_content_wire_type() { + fn nested_json_content_uses_content_wire_type() { let frame = json_to_frame( "MessageEdit", json!({ @@ -1150,35 +1112,24 @@ mod tests { let message = frame.get_data(DataType::Message).unwrap(); assert_eq!( - container_value(message, DataType::AppContent).and_then(DataValue::as_str), + container_value_by_name(message, "Content").and_then(DataValue::as_str), Some("ciphertext") ); } #[test] - fn app_content_is_exposed_as_content_to_frontend() { + fn content_is_exposed_to_frontend() { let frame = CommunicationValue::new(CommunicationType::MessageEditLive) .with_id(1) - .add_typed_default(DataType::AppContent, DataValue::Str("ciphertext".into())); + .add_typed_default(DataType::Content, DataValue::Str("ciphertext".into())); let json = frame_to_json(&frame).unwrap(); assert_eq!(json["data"]["Content"], "ciphertext"); - assert!(json["data"].get("AppContent").is_none()); - } - - #[test] - fn translated_field_collisions_are_rejected() { - assert!(json_to_frame( - "MessageEdit", - json!({ "Content": "a", "AppContent": "b" }), - 1, - ) - .is_err()); } fn valid_initial_state() -> CommunicationValue { - CommunicationValue::new(CommunicationType::ClientStateSync) + CommunicationValue::new(communication_type("ClientStateSync").unwrap()) .add_typed_default(DataType::SessionId, DataValue::UnsignedNumber(1)) .add_typed_default(DataType::VersionNumber, DataValue::UnsignedNumber(0)) .add_typed_default(DataType::CacheSchemaVersion, DataValue::UnsignedNumber(0)) @@ -1195,7 +1146,7 @@ mod tests { let (state, ack) = prepare_initial_state_ack(&valid_initial_state(), &ids).unwrap(); assert_eq!(state["SyncMode"], "full"); - assert!(ack.is_type(CommunicationType::ClientStateAck)); + assert_eq!(ack.get_type_name(), Some("ClientStateAck")); assert_eq!(ack.id(), Some(1)); } @@ -1216,7 +1167,7 @@ mod tests { #[test] fn malformed_nested_initial_state_does_not_prepare_ack() { let ids = RequestIdAllocator::new(); - let malformed = CommunicationValue::new(CommunicationType::ClientStateSync) + let malformed = CommunicationValue::new(communication_type("ClientStateSync").unwrap()) .add_typed_default(DataType::SessionId, DataValue::UnsignedNumber(1)) .add_typed_default(DataType::VersionNumber, DataValue::UnsignedNumber(0)) .add_typed_default(DataType::CacheSchemaVersion, DataValue::UnsignedNumber(0)) diff --git a/packages/cache/src/sync.tsx b/packages/cache/src/sync.tsx index 37076c1..8928e23 100644 --- a/packages/cache/src/sync.tsx +++ b/packages/cache/src/sync.tsx @@ -21,8 +21,7 @@ export function removeMissingContactSnapshots( } export default function CacheSync() { - const { addInterceptor, contextReady, freshContacts, subscribePush } = - useMTP(); + const { addInterceptor, contextReady, freshContacts, subscribe } = useMTP(); const { load } = useStorage(); const [accountId, setAccountId] = useState(0); const queueRef = useRef(Promise.resolve()); @@ -321,10 +320,19 @@ export default function CacheSync() { useEffect(() => { if (!accountId || !contextReady) return; - return subscribePush((message) => { + const handleMessage = (message: ProtocolMessage) => { void enqueue(() => synchronizePush(message)); - }); - }, [accountId, contextReady, enqueue, subscribePush, synchronizePush]); + }; + const unsubscribers = [ + subscribe("GetStates", handleMessage), + subscribe("MessageLive", handleMessage), + subscribe("MessageEditLive", handleMessage), + subscribe("MessageDeleteLive", handleMessage), + subscribe("MessageState", handleMessage), + subscribe("MessageReactionLive", handleMessage), + ]; + return () => unsubscribers.forEach((unsubscribe) => unsubscribe()); + }, [accountId, contextReady, enqueue, subscribe, synchronizePush]); return null; } diff --git a/packages/call/src/store.tsx b/packages/call/src/store.tsx index 6f7f524..bbf3f4e 100644 --- a/packages/call/src/store.tsx +++ b/packages/call/src/store.tsx @@ -1223,7 +1223,7 @@ export const useCall = create<{ export function useInitializeCall() { const navigate = useNavigate(); const location = useLocation(); - const { send, subscribePush } = useMTP(); + const { send, subscribe } = useMTP(); const { load } = useStorage(); const { insertCall } = useSession(); const { get } = useUser(); @@ -1313,14 +1313,9 @@ export function useInitializeCall() { // listen to call invites useEffect(() => { - return subscribePush(async (message) => { - if (message.type !== "CallInvite") return; - - const { CallId, CallSecret, SenderId } = message.data as { - CallId: string; - CallSecret: ProtocolCallSecret; - SenderId: number; - }; + return subscribe("CallInvite", async ({ data }) => { + const { CallId, CallSecret, SenderId } = data; + if (!CallId || !CallSecret || !SenderId) return; if (SenderId === Number(await load("user_id"))) { return; @@ -1337,7 +1332,7 @@ export function useInitializeCall() { SenderId, ); }); - }, [load, subscribePush, showCallingScreen]); + }, [load, subscribe, showCallingScreen]); // get callId from url useEffect(() => { diff --git a/packages/chat/src/context.tsx b/packages/chat/src/context.tsx index b4f1f5b..7c88df1 100644 --- a/packages/chat/src/context.tsx +++ b/packages/chat/src/context.tsx @@ -226,7 +226,7 @@ export async function fetchReplyMessage({ export default function Provider({ children }: { children: ReactNode }) { const { load } = useStorage(); - const { send, subscribePush } = useMTP(); + const { send, subscribe } = useMTP(); const { get: getUser } = useUser(); const { moveUserIdToTop } = useSession(); @@ -912,124 +912,47 @@ export default function Provider({ children }: { children: ReactNode }) { // Get live updates for message states useEffect(() => { - return subscribePush((message) => { - if (message.type === "MessageEditLive") { - if (!currentChatSecret) return; - - const rawData = message.data as { - ChatPartnerId: unknown; - SendTime: unknown; - Content: string; - }; - - const chatPartnerId = Number(rawData.ChatPartnerId); - const sendTime = Number(rawData.SendTime); - - if (!Number.isFinite(chatPartnerId) || !Number.isFinite(sendTime)) { - log( - 3, - "chat", - "yellow", - "Cancel message edit update due to invalid data", - ); - return; - } - - if (chatPartnerId !== userIdValue) { - log( - 3, - "chat", - "yellow", - "Cancel message edit update due to user ID mismatch", - { - expected: userIdValue, - received: chatPartnerId, - }, - ); - return; - } - - void decryptChatText(currentChatSecret, rawData.Content) - .then((content) => { - editMessage(sendTime, { Content: content, Edited: true }); - }) - .catch((err) => { - log(1, "chat", "red", "Failed to decrypt message edit", err, { - SendTime: sendTime, - }); - }); - return; - } - - if (message.type === "MessageReactionLive") { - const rawData = message.data as { - ChatPartnerId: unknown; - SendTime: unknown; - Reaction: string; - SenderId: unknown; - Accepted: boolean; - }; - const chatPartnerId = Number(rawData.ChatPartnerId); - const sendTime = Number(rawData.SendTime); - const senderId = Number(rawData.SenderId); - - if ( - chatPartnerId !== userIdValue || - !Number.isFinite(sendTime) || - !Number.isFinite(senderId) - ) { - return; - } - - applyLiveReaction( - sendTime, - rawData.Reaction, - senderId, - rawData.Accepted, - ); - return; - } - - if (message.type === "MessageDeleteLive") { - const data = message.data as { - ChatPartnerId: number; - SendTime: number; - }; - - if (data.ChatPartnerId !== userIdValue) return; - - removeMessage(data.SendTime); - return; - } - - if (message.type !== "MessageState") return; - - const rawData = message.data as { - ChatPartnerId: unknown; - SendTime: unknown; - MessageState: RawMessage["MessageState"]; - }; - - const nextState = { - ChatPartnerId: Number(rawData.ChatPartnerId), - SendTime: Number(rawData.SendTime), - MessageState: rawData.MessageState, - }; - - if ( - !Number.isFinite(nextState.ChatPartnerId) || - !Number.isFinite(nextState.SendTime) - ) { + const unsubscribeEdit = subscribe("MessageEditLive", ({ data }) => { + if (!currentChatSecret) return; + if (data.ChatPartnerId !== userIdValue) { log( 3, "chat", "yellow", - "Cancel message state update due to invalid data", + "Cancel message edit update due to user ID mismatch", + { + expected: userIdValue, + received: data.ChatPartnerId, + }, ); return; } - if (nextState.ChatPartnerId !== userIdValue) { + void decryptChatText(currentChatSecret, data.Content) + .then((content) => { + editMessage(data.SendTime, { Content: content, Edited: true }); + }) + .catch((err) => { + log(1, "chat", "red", "Failed to decrypt message edit", err, { + SendTime: data.SendTime, + }); + }); + }); + const unsubscribeReaction = subscribe("MessageReactionLive", ({ data }) => { + if (data.ChatPartnerId !== userIdValue) return; + applyLiveReaction( + data.SendTime, + data.Reaction, + data.SenderId, + data.Accepted, + ); + }); + const unsubscribeDelete = subscribe("MessageDeleteLive", ({ data }) => { + if (data.ChatPartnerId !== userIdValue) return; + removeMessage(data.SendTime); + }); + const unsubscribeState = subscribe("MessageState", ({ data }) => { + if (data.ChatPartnerId !== userIdValue) { log( 3, "chat", @@ -1037,22 +960,27 @@ export default function Provider({ children }: { children: ReactNode }) { "Cancel message state update due to user ID mismatch", { expected: userIdValue, - received: nextState.ChatPartnerId, + received: data.ChatPartnerId, }, ); return; } - - editMessage(nextState.SendTime, { - MessageState: nextState.MessageState, + editMessage(data.SendTime, { + MessageState: data.MessageState, }); }); + return () => { + unsubscribeEdit(); + unsubscribeReaction(); + unsubscribeDelete(); + unsubscribeState(); + }; }, [ currentChatSecret, applyLiveReaction, editMessage, removeMessage, - subscribePush, + subscribe, userIdValue, ]); diff --git a/packages/markdown/src/markdown.tsx b/packages/markdown/src/markdown.tsx index cd2a210..f8684c4 100644 --- a/packages/markdown/src/markdown.tsx +++ b/packages/markdown/src/markdown.tsx @@ -159,7 +159,7 @@ function CopyableCode({ * @param input Parameter input. * @returns InlineNode[]. */ -export function parseInlineNodes(input: string): InlineNode[] { +function parseInlineNodes(input: string): InlineNode[] { const nodes: InlineNode[] = []; let cursor = 0; @@ -205,7 +205,7 @@ export function parseInlineNodes(input: string): InlineNode[] { return nodes; } -export function parseEmojiText(input: string): InlineNode[] { +function parseEmojiText(input: string): InlineNode[] { const nodes: InlineNode[] = []; let cursor = 0; diff --git a/packages/mtp/package.json b/packages/mtp/package.json index e036029..44f5750 100644 --- a/packages/mtp/package.json +++ b/packages/mtp/package.json @@ -9,19 +9,16 @@ "scripts": { "format": "pnpm exec prettier --write .", "lint": "eslint src --ext .ts,.tsx", - "test": "vitest run", + "test": "vitest run --passWithNoTests", "build": "pnpm run test && tsc -p tsconfig.json --noEmit" }, "dependencies": { "@methanium/ui": "*", "@tauri-apps/api": "^2.11.1", - "@tensamin/crypto": "workspace:*", "@tensamin/shared": "workspace:*", "@tensamin/storage": "workspace:*", "mtp": "*", - "react": "^19.2.8", - "react-dom": "^19.2.8", - "zod": "^4.4.3" + "react": "^19.2.8" }, "devDependencies": { "eslint": "^10.8.0" diff --git a/packages/mtp/src/browser.tsx b/packages/mtp/src/browser.tsx new file mode 100644 index 0000000..755a021 --- /dev/null +++ b/packages/mtp/src/browser.tsx @@ -0,0 +1,529 @@ +import { type ReactNode, useEffect, useMemo, useRef, useState } from "react"; +import { toast as sonnerToast } from "@methanium/ui"; +import { base64ToBytes, ConnectionState, MTPClient } from "mtp"; +import createAsyncQueue from "@tensamin/shared/asyncQueue"; +import { + mtp as mtpSchemas, + type Calls, + type Communities, + type Contacts, +} from "@tensamin/shared/data"; +import { log } from "@tensamin/shared/log"; +import { useStorage } from "@tensamin/storage/context"; + +import { + type BoundSendFn, + MTPContext, + type MTPContextType, + type ProtocolMessage, + removeMissingContacts, + useMessageHandlers, +} from "./mtpContext"; +import { + DISCOVERY_TIMEOUT, + INITIAL_SYNC_TIMEOUT, + RECONNECT_JITTER, + RECONNECT_LONG_INTERVAL, + RECONNECT_RESET, + RECONNECT_TRIES, + RETRY_INTERVAL, + STATE_ACK_TIMEOUT, +} from "./values"; + +type BrowserMtpClient = Awaited>; + +function createBrowserClient( + options: Omit[0], "schemas">, +) { + return MTPClient.create({ + ...options, + schemas: mtpSchemas, + throwProtocolErrors: true, + onValidationError: (error) => { + log(1, "mtp", "red", "Failed to validate push message", error); + }, + }); +} + +function abortError(signal: AbortSignal): Error { + return signal.reason instanceof Error + ? signal.reason + : new Error("Initial state synchronization was cancelled"); +} + +function withDeadline( + promise: Promise, + timeoutMs: number, + timeoutMessage: string, + signal: AbortSignal, +): Promise { + return new Promise((resolve, reject) => { + if (signal.aborted) { + reject(abortError(signal)); + return; + } + let settled = false; + const finish = (complete: () => void) => { + if (settled) return; + settled = true; + clearTimeout(timeout); + signal.removeEventListener("abort", onAbort); + complete(); + }; + const timeout = setTimeout( + () => finish(() => reject(new Error(timeoutMessage))), + timeoutMs, + ); + const onAbort = () => finish(() => reject(abortError(signal))); + signal.addEventListener("abort", onAbort, { once: true }); + promise.then( + (value) => finish(() => resolve(value)), + (error: unknown) => finish(() => reject(error)), + ); + }); +} + +async function completeInitialSynchronization( + client: BrowserMtpClient, + subscribe: MTPContextType["subscribe"], + signal: AbortSignal, + syncTimeoutMs = INITIAL_SYNC_TIMEOUT, + ackTimeoutMs = STATE_ACK_TIMEOUT, +): Promise> { + const stateSync = new Promise>( + (resolve, reject) => { + let unsubscribeStateSync = () => {}; + let unsubscribeNoIota = () => {}; + const cleanup = () => { + clearTimeout(timeout); + unsubscribeStateSync(); + unsubscribeNoIota(); + signal.removeEventListener("abort", onAbort); + }; + const onAbort = () => { + cleanup(); + reject(abortError(signal)); + }; + const timeout = setTimeout(() => { + cleanup(); + reject(new Error("Initial state synchronization timed out")); + }, syncTimeoutMs); + signal.addEventListener("abort", onAbort, { once: true }); + if (signal.aborted) { + onAbort(); + return; + } + unsubscribeStateSync = subscribe("ClientStateSync", (message) => { + cleanup(); + resolve(message); + }); + unsubscribeNoIota = subscribe("ErrorNoIota", () => { + cleanup(); + reject(new Error("No Iota is currently connected")); + }); + }, + ); + const [, state] = await Promise.all([ + withDeadline( + client.auth(), + syncTimeoutMs, + "MTP authentication timed out", + signal, + ), + stateSync, + ]); + await withDeadline( + client.request("ClientStateAck", { + SessionId: state.data.SessionId, + VersionNumber: state.data.VersionNumber, + }), + ackTimeoutMs, + "State acknowledgement timed out", + signal, + ); + if (signal.aborted) throw abortError(signal); + return state; +} + +function protocolErrorDetails(error: unknown) { + if (typeof error !== "object" || error === null || !("type" in error)) { + return null; + } + const protocolError = error as { + id?: unknown; + type?: unknown; + frame?: unknown; + }; + return { + id: protocolError.id, + type: protocolError.type, + frame: protocolError.frame, + }; +} + +export function BrowserProvider(props: { + children: ReactNode; + blockConnection?: boolean; +}) { + const { load } = useStorage(); + const [readyState, setReadyState] = useState( + ConnectionState.Disconnected, + ); + const [identified, setIdentified] = useState(false); + const [identifying, setIdentifying] = useState(false); + const [freshCommunities, setFreshCommunities] = useState([]); + const [freshContacts, setFreshContacts] = useState([]); + const [freshCalls, setFreshCalls] = useState([]); + const clientRef = useRef(null); + const { addInterceptor, attachSubscriptions, interceptorsRef, subscribe } = + useMessageHandlers(); + const connected = readyState === ConnectionState.Connected; + + const [mtpUrl, setMtpUrl] = useState(null); + useEffect(() => { + load("omega_url").then(setMtpUrl); + }, [load]); + + const send: BoundSendFn = useMemo( + () => async (type, data, options) => { + const client = clientRef.current; + if (!client) throw new Error("mtp is not connected"); + const response = await client.request(type, data, options); + if (response.type === "GetStates") { + setFreshContacts((contacts) => + removeMissingContacts( + contacts, + response as ProtocolMessage<"GetStates">, + ), + ); + } + return response; + }, + [], + ); + + const resolveConnectionRef = useRef(() => {}); + useEffect(() => { + if (!mtpUrl) return; + let attempts = 0; + let reconnectTimer: ReturnType | null = null; + let reconnectResetTimer: ReturnType | null = null; + let reconnectScheduled = false; + let disposed = false; + let connectionGeneration = 0; + let cleanupConnection = () => {}; + + const clearReconnectTimer = () => { + if (!reconnectTimer) return; + clearTimeout(reconnectTimer); + reconnectTimer = null; + reconnectScheduled = false; + }; + const clearReconnectResetTimer = () => { + if (!reconnectResetTimer) return; + clearTimeout(reconnectResetTimer); + reconnectResetTimer = null; + }; + const scheduleReconnect = (error: unknown) => { + if (disposed || reconnectScheduled) return; + attempts += 1; + const shortRetry = attempts <= RECONNECT_TRIES; + if (!shortRetry) { + log(0, "mtp", "red", "Reconnection attempts exhausted", error); + sonnerToast.error("Connection failed", { + id: "mtp-connection-toast", + description: + error instanceof Error + ? `${error.message.split(":")[0]}. Retrying in the background.` + : "Connection lost. Retrying in the background.", + icon: null, + duration: Infinity, + closeButton: true, + promise: null, + } as unknown as Parameters[1]); + } else { + sonnerToast.loading( + `Reconnecting to server... (attempt ${attempts} of ${RECONNECT_TRIES})`, + { id: "mtp-connection-toast" }, + ); + } + const baseDelay = shortRetry ? RETRY_INTERVAL : RECONNECT_LONG_INTERVAL; + const jitter = 1 + (Math.random() * 2 - 1) * RECONNECT_JITTER; + reconnectScheduled = true; + reconnectTimer = setTimeout( + () => { + reconnectScheduled = false; + reconnectTimer = null; + void connect(); + }, + Math.round(baseDelay * jitter), + ); + }; + + async function connect() { + if (disposed || props.blockConnection) return; + const generation = ++connectionGeneration; + let client: BrowserMtpClient | null = null; + let failed = false; + let connectionReady = false; + let detachSubscriptions = () => {}; + let unsubscribeNoIota = () => {}; + const attemptAbort = new AbortController(); + const cleanup = () => { + attemptAbort.abort( + new Error("Initial state synchronization was cancelled"), + ); + unsubscribeNoIota(); + detachSubscriptions(); + client?.disconnect(); + if (clientRef.current === client) clientRef.current = null; + clearReconnectResetTimer(); + if (generation === connectionGeneration) { + setReadyState(ConnectionState.Disconnected); + setIdentified(false); + setIdentifying(false); + } + }; + cleanupConnection = cleanup; + try { + setIdentified(false); + setIdentifying(false); + const [userId, keyring] = await Promise.all([ + load("user_id"), + load("mtp_keyring"), + ]); + if (!userId || !keyring) throw new Error("Missing login credentials"); + const forcedOmikronUrl = await load("forced_omikron_url"); + const forcedOmikronPublicKey = await load("forced_omikron_public_key"); + let url = null; + let omikronPublicKey = null; + if (forcedOmikronUrl && forcedOmikronPublicKey) { + url = forcedOmikronUrl; + omikronPublicKey = forcedOmikronPublicKey; + } else { + log(2, "mtp", "purple", "Fetching Omikron data."); + const data = await fetch(`${mtpUrl}api/get/omikron/${userId}`, { + signal: AbortSignal.any([ + attemptAbort.signal, + AbortSignal.timeout(DISCOVERY_TIMEOUT), + ]), + }); + if (data.status === 404) { + throw new Error("No Omikron assignment is currently available"); + } + if (!data.ok) + throw new Error(`Omikron discovery failed: HTTP ${data.status}`); + const omikronData = (await data.json()) as { + ip_address: string; + port: number; + public_key: string; + }; + if ( + !omikronData.ip_address || + !omikronData.port || + !omikronData.public_key + ) { + throw new Error("Invalid Omikron data"); + } + url = `https://${omikronData.ip_address}:${omikronData.port}`; + omikronPublicKey = omikronData.public_key; + } + if (!url || !omikronPublicKey) { + throw new Error("Missing Omikron URL or Public Key"); + } + log(2, "mtp", "green", "Connecting to: " + url); + client = await createBrowserClient({ + url, + credentials: { clientId: userId, keyring: base64ToBytes(keyring) }, + hostPublicKey: { value: omikronPublicKey, encoding: "base64" }, + descriptor: "client", + pings: true, + logger: (event) => { + if (event.type === "state") { + if (generation !== connectionGeneration) return; + const state = client?.state ?? ConnectionState.Disconnected; + setReadyState(state); + if ( + state === ConnectionState.Disconnected && + clientRef.current === client && + !failed + ) { + failed = true; + const error = new Error("MTP connection lost"); + attemptAbort.abort(error); + if (connectionReady) { + cleanup(); + scheduleReconnect(error); + } + } + } + if (event.type !== "Pong" && event.type !== "Ping") { + log( + 2, + "mtp", + event.type === "state" + ? "purple" + : event.direction === "recv" + ? "cyan" + : event.direction === "send" + ? "gray" + : "blue", + event.type === "state" + ? event.data + : event.direction === "recv" + ? "< " + event.type + : event.direction === "send" + ? "> " + event.type + : event.type, + event, + ); + } + }, + }); + if (disposed || generation !== connectionGeneration) { + client.disconnect(); + return; + } + const activeClient = client; + clientRef.current = activeClient; + detachSubscriptions = attachSubscriptions(activeClient); + unsubscribeNoIota = subscribe("ErrorNoIota", () => { + if (clientRef.current !== activeClient || failed) return; + failed = true; + const error = new Error("No Iota is currently connected"); + attemptAbort.abort(error); + cleanup(); + scheduleReconnect(error); + }); + setReadyState(activeClient.state); + setIdentifying(true); + const finalResponse = await completeInitialSynchronization( + activeClient, + subscribe, + attemptAbort.signal, + ); + if (disposed || clientRef.current !== activeClient) return; + setFreshContacts(finalResponse.data.Contacts); + setFreshCommunities(finalResponse.data.Communities); + setFreshCalls(finalResponse.data.Calls); + connectionReady = true; + setIdentifying(false); + setIdentified(true); + clearReconnectTimer(); + clearReconnectResetTimer(); + reconnectResetTimer = setTimeout(() => { + attempts = 0; + reconnectResetTimer = null; + }, RECONNECT_RESET * 1_000); + resolveConnectionRef.current?.(); + } catch (connectError) { + if (disposed || generation !== connectionGeneration) { + client?.disconnect(); + return; + } + failed = true; + cleanup(); + const message = + connectError instanceof Error + ? connectError.message + : String(connectError ?? "Unknown error"); + log( + 0, + "mtp", + "red", + `Connection/authentication attempt failed: ${message}`, + protocolErrorDetails(connectError) ?? connectError, + ); + scheduleReconnect(connectError); + } + } + + void connect(); + return () => { + disposed = true; + clearReconnectTimer(); + clearReconnectResetTimer(); + cleanupConnection(); + setReadyState(ConnectionState.Disconnected); + setIdentified(false); + setIdentifying(false); + sonnerToast.dismiss("mtp-connection-toast"); + }; + }, [attachSubscriptions, load, mtpUrl, props.blockConnection, subscribe]); + + useEffect(() => { + return subscribe("ErrorNoIota", () => { + setIdentified(false); + setIdentifying(false); + sonnerToast.error("We couldn't reach your Iota", { + description: + "Check your network connection and try restarting your Iota", + icon: null, + duration: Infinity, + closeButton: true, + }); + resolveConnectionRef.current?.(); + }); + }, [subscribe]); + + useEffect( + () => + subscribe("GetStates", (message) => { + setFreshContacts((contacts) => + removeMissingContacts(contacts, message), + ); + }), + [subscribe], + ); + + const loadingDescription = useMemo(() => { + if (!mtpUrl) return "Loading connection details"; + if (readyState === ConnectionState.Connecting || !connected) { + return "Establishing transport channel"; + } + if (identifying || !identified) return "Waiting for authenticated session"; + return "Loading..."; + }, [connected, identified, identifying, readyState, mtpUrl]); + const contextReady = connected && identified && mtpUrl !== null; + const mtpRef = useMemo(() => createAsyncQueue<{ send: typeof send }>(), []); + useEffect(() => { + if (connected && identified && mtpUrl) { + mtpRef.set({ send }); + } + }, [connected, identified, mtpUrl, send, mtpRef]); + + const sendQueued: BoundSendFn = useMemo( + () => async (type, data, options) => { + const mtp = await mtpRef.get(); + const response = await mtp.send(type, data, options); + for (const interceptor of interceptorsRef.current) { + void Promise.resolve(interceptor({ type, data, response })).catch( + (error) => { + log(1, "mtp", "yellow", "MTP interceptor failed", error, { type }); + }, + ); + } + return response; + }, + [interceptorsRef, mtpRef], + ); + + return ( + + {props.children} + + ); +} diff --git a/packages/mtp/src/context.test.tsx b/packages/mtp/src/context.test.tsx deleted file mode 100644 index b15043a..0000000 --- a/packages/mtp/src/context.test.tsx +++ /dev/null @@ -1,220 +0,0 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; - -import { RequestIdAllocator } from "./requestIds"; - -vi.mock("@methanium/ui", () => ({ - toast: { - dismiss: vi.fn(), - error: vi.fn(), - loading: vi.fn(), - }, -})); - -vi.mock("@tensamin/shared/log", () => ({ log: vi.fn() })); -vi.mock("@tensamin/storage/context", () => ({ - useStorage: () => ({ load: vi.fn() }), -})); - -const { completeInitialSynchronization, isPushType, validateResponse } = - await import("./context"); - -const validState = { - SessionId: 7, - VersionNumber: 2, - CacheSchemaVersion: 0, - SyncMode: "full", - Contacts: [], - Communities: [], - Calls: [], - Messages: [], - DeletedMessageIds: [], - DeletedContactIds: [], -}; - -function mockInitialSyncClient( - state: { type: string; data: unknown } = { - type: "ClientStateSync", - data: validState, - }, - acknowledgement: unknown = { type: "ClientStateAck", data: {} }, -) { - const handlers = new Map void>(); - const request = vi.fn().mockResolvedValue(acknowledgement); - const client = { - auth: vi.fn(async () => { - handlers.get(state.type)?.(state as never); - }), - subscribe: vi.fn((type: string, handler: (message: never) => void) => { - handlers.set(type, handler); - return () => handlers.delete(type); - }), - request, - disconnect: vi.fn(), - } as unknown as Parameters[0]; - return { client, handlers, request }; -} - -afterEach(() => { - vi.useRealTimers(); -}); - -describe("MTP protocol dispatch", () => { - it("preserves protocol errors for the request layer", () => { - const error = validateResponse("GetStates", { - id: 12, - type: "ErrorInternal", - data: { ErrorType: "temporary" }, - }); - expect(error.type).toBe("ErrorInternal"); - expect(error.id).toBe(12); - }); - - it("recognizes initial and live presence pushes", () => { - expect(isPushType("GetStates")).toBe(true); - expect(isPushType("ClientChanged")).toBe(true); - expect(isPushType("UnknownMessage")).toBe(false); - }); -}); - -describe("browser initial synchronization", () => { - it("validates state, sends a nonzero acknowledgement, then resolves", async () => { - const { client, request } = mockInitialSyncClient(); - - const state = await completeInitialSynchronization( - client, - new RequestIdAllocator(), - new AbortController().signal, - ); - - expect(state.data).toEqual(validState); - expect(request).toHaveBeenCalledWith( - "ClientStateAck", - { SessionId: 7, VersionNumber: 2 }, - { id: 1 }, - ); - }); - - it("does not acknowledge malformed state", async () => { - const { client, request } = mockInitialSyncClient({ - type: "ClientStateSync", - data: { ...validState, SyncMode: "invalid" }, - }); - - await expect( - completeInitialSynchronization( - client, - new RequestIdAllocator(), - new AbortController().signal, - ), - ).rejects.toThrow("Response validation failed"); - expect(request).not.toHaveBeenCalled(); - }); - - it("rejects ErrorNoIota during initial synchronization", async () => { - const { client, request } = mockInitialSyncClient({ - type: "ErrorNoIota", - data: {}, - }); - - await expect( - completeInitialSynchronization( - client, - new RequestIdAllocator(), - new AbortController().signal, - ), - ).rejects.toThrow("No Iota is currently connected"); - expect(request).not.toHaveBeenCalled(); - }); - - it("rejects an acknowledgement protocol error", async () => { - const { client } = mockInitialSyncClient(undefined, { - type: "ErrorInvalidData", - data: {}, - }); - - await expect( - completeInitialSynchronization( - client, - new RequestIdAllocator(), - new AbortController().signal, - ), - ).rejects.toThrow("State acknowledgement failed: ErrorInvalidData"); - }); - - it("times out a missing acknowledgement", async () => { - vi.useFakeTimers(); - const { client } = mockInitialSyncClient(); - vi.mocked(client.request).mockReturnValue(new Promise(() => {})); - const result = completeInitialSynchronization( - client, - new RequestIdAllocator(), - new AbortController().signal, - 100, - 10, - ); - const assertion = expect(result).rejects.toThrow( - "State acknowledgement timed out", - ); - - await vi.advanceTimersByTimeAsync(10); - await assertion; - }); - - it("stops immediately when the connection attempt is cancelled", async () => { - const { client } = mockInitialSyncClient(); - vi.mocked(client.auth).mockImplementation(() => new Promise(() => {})); - const controller = new AbortController(); - const result = completeInitialSynchronization( - client, - new RequestIdAllocator(), - controller.signal, - ); - - controller.abort(new Error("MTP connection lost")); - await expect(result).rejects.toThrow("MTP connection lost"); - }); - - it("times out authentication while waiting for initial state", async () => { - vi.useFakeTimers(); - const { client, handlers } = mockInitialSyncClient(); - vi.mocked(client.auth).mockImplementation(() => { - handlers.get("ClientStateSync")?.({ - type: "ClientStateSync", - data: validState, - } as never); - return new Promise(() => {}); - }); - const result = completeInitialSynchronization( - client, - new RequestIdAllocator(), - new AbortController().signal, - 100, - 10, - ); - const assertion = expect(result).rejects.toThrow( - "MTP authentication timed out", - ); - - await vi.advanceTimersByTimeAsync(100); - await assertion; - }); - - it("uses a fresh request ID namespace for each connection", async () => { - const first = mockInitialSyncClient(); - const second = mockInitialSyncClient(); - - await completeInitialSynchronization( - first.client, - new RequestIdAllocator(), - new AbortController().signal, - ); - await completeInitialSynchronization( - second.client, - new RequestIdAllocator(), - new AbortController().signal, - ); - - expect(first.request.mock.calls[0]?.[2]).toEqual({ id: 1 }); - expect(second.request.mock.calls[0]?.[2]).toEqual({ id: 1 }); - }); -}); diff --git a/packages/mtp/src/context.tsx b/packages/mtp/src/context.tsx index 53c1862..c07579f 100644 --- a/packages/mtp/src/context.tsx +++ b/packages/mtp/src/context.tsx @@ -1,1110 +1,41 @@ -import { - createContext, - type ReactNode, - useCallback, - useContext, - useEffect, - useMemo, - useRef, - useState, -} from "react"; -import { invoke, isTauri } from "@tauri-apps/api/core"; -import { listen, type UnlistenFn } from "@tauri-apps/api/event"; +import { type ReactNode, useContext, useEffect, useState } from "react"; +import { isTauri } from "@tauri-apps/api/core"; import { MTPClient } from "mtp"; -import { type z } from "zod"; -import { ConnectionState } from "mtp"; -import createAsyncQueue from "@tensamin/shared/asyncQueue"; -import { toast as sonnerToast } from "@methanium/ui"; -import { - type Calls, - type Communities, - type Contacts, - mtp as schemas, - type MTP as Schemas, -} from "@tensamin/shared/data"; -import { log } from "@tensamin/shared/log"; -import { ProtocolError } from "@tensamin/shared/errors"; -import { useStorage } from "@tensamin/storage/context"; - -import { fromWireMessage, toWireData } from "./protocolFields"; -import { RequestIdAllocator } from "./requestIds"; -import { - DISCOVERY_TIMEOUT, - INITIAL_SYNC_TIMEOUT, - RECONNECT_JITTER, - RECONNECT_LONG_INTERVAL, - RECONNECT_RESET, - RECONNECT_TRIES, - RETRY_INTERVAL, - STATE_ACK_TIMEOUT, -} from "./values"; - -type BrowserMtpClient = Awaited>; - -function base64ToUint8Array(b64: string) { - const bin = atob(b64); - const out = new Uint8Array(bin.length); - - for (let i = 0; i < bin.length; i++) { - out[i] = bin.charCodeAt(i); - } - - return out; -} - -export type ProtocolMessage< - T extends keyof Schemas & string = keyof Schemas & string, -> = { - id?: number; - type: T | string; - data: z.infer; -}; - -export type BoundSendFn = ( - type: T, - data?: z.infer, -) => Promise>; - -export type PushHandler = (message: ProtocolMessage) => void | Promise; - -const PUSH_TYPES = [ - "MessageLive", - "MessageEditLive", - "MessageReactionLive", - "MessageDeleteLive", - "MessageState", - "CallInvite", - "GetStates", - "ClientChanged", - "ErrorNoIota", -] as const; - -export function isPushType(type: string): boolean { - return (PUSH_TYPES as readonly string[]).includes(type); -} - -function normalizeMtpMessage(message: T): T { - return fromWireMessage(message); -} - -async function requestWithId( - client: BrowserMtpClient, - ids: RequestIdAllocator, - type: string, - data: Record, -) { - let id: number; - try { - id = ids.allocate(); - } catch (error) { - client.disconnect(); - throw error; - } - - return client.request(type, toWireData(data) as Record, { - id, - }); -} - -function removeMissingContacts( - contacts: Contacts, - message: ProtocolMessage, -): Contacts { - if (message.type !== "GetStates") return contacts; - const data = message.data as { MissingUserIds?: unknown }; - if (!Array.isArray(data.MissingUserIds)) return contacts; - const missing = new Set( - data.MissingUserIds.filter( - (userId): userId is number => typeof userId === "number", - ), - ); - return contacts.filter((contact) => !missing.has(contact.UserId)); -} - -export type MTPExchange = { - type: keyof Schemas & string; - data: unknown; - response: ProtocolMessage; -}; - -export type MTPInterceptor = (exchange: MTPExchange) => void | Promise; - -type ContextType = { - send: BoundSendFn; - subscribe: ( - type: T, - handler: (message: ProtocolMessage) => void, - ) => () => void; - subscribePush: (handler: PushHandler) => () => void; - addInterceptor: (interceptor: MTPInterceptor) => () => void; - readyState: number; - identified: boolean; - freshContacts: Contacts; - freshCommunities: Communities; - freshCalls: Calls; - contextReady: boolean; - loadingDescription: string; -}; - -const MTPContext = createContext(undefined); - -function getProtocolErrorDetails(error: unknown) { - if (typeof error !== "object" || error === null || !("type" in error)) { - return null; - } - - const protocolError = error as { - id?: unknown; - type?: unknown; - data?: unknown; - }; - return { - id: protocolError.id, - type: protocolError.type, - data: protocolError.data, - }; -} - -// Zod schema validation -export function validateResponse( - type: T, - message: { id?: number; type: string; data: unknown }, -): ProtocolMessage { - if (message.type.startsWith("Error")) { - return message as ProtocolMessage; - } - - const schema = - schemas[message.type as keyof Schemas & string]?.response ?? - schemas[type]?.response; - if (!schema) { - return message as ProtocolMessage; - } - - const parsed = schema.safeParse(message.data); - if (!parsed.success) { - throw new Error( - `Response validation failed for ${type}: ${parsed.error.message}`, - ); - } - - return { - id: message.id, - type: message.type, - data: parsed.data, - } as ProtocolMessage; -} - -function abortError(signal: AbortSignal): Error { - return signal.reason instanceof Error - ? signal.reason - : new Error("Initial state synchronization was cancelled"); -} - -function withDeadline( - promise: Promise, - timeoutMs: number, - timeoutMessage: string, - signal: AbortSignal, -): Promise { - return new Promise((resolve, reject) => { - if (signal.aborted) { - reject(abortError(signal)); - return; - } - let settled = false; - const finish = (complete: () => void) => { - if (settled) return; - settled = true; - clearTimeout(timeout); - signal.removeEventListener("abort", onAbort); - complete(); - }; - const timeout = setTimeout( - () => finish(() => reject(new Error(timeoutMessage))), - timeoutMs, - ); - const onAbort = () => finish(() => reject(abortError(signal))); - signal.addEventListener("abort", onAbort, { once: true }); - promise.then( - (value) => finish(() => resolve(value)), - (error: unknown) => finish(() => reject(error)), - ); - }); -} - -export async function completeInitialSynchronization( - client: BrowserMtpClient, - ids: RequestIdAllocator, - signal: AbortSignal, - syncTimeoutMs = INITIAL_SYNC_TIMEOUT, - ackTimeoutMs = STATE_ACK_TIMEOUT, -): Promise> { - const stateSync = new Promise>( - (resolve, reject) => { - let unsubscribeStateSync = () => {}; - let unsubscribeNoIota = () => {}; - const cleanup = () => { - clearTimeout(timeout); - unsubscribeStateSync(); - unsubscribeNoIota(); - signal.removeEventListener("abort", onAbort); - }; - const onAbort = () => { - cleanup(); - reject(abortError(signal)); - }; - const timeout = setTimeout(() => { - cleanup(); - reject(new Error("Initial state synchronization timed out")); - }, syncTimeoutMs); - signal.addEventListener("abort", onAbort, { once: true }); - if (signal.aborted) { - onAbort(); - return; - } - unsubscribeStateSync = client.subscribe("ClientStateSync", (message) => { - cleanup(); - try { - resolve( - validateResponse("ClientStateSync", normalizeMtpMessage(message)), - ); - } catch (error) { - reject(error); - } - }); - unsubscribeNoIota = client.subscribe("ErrorNoIota", () => { - cleanup(); - reject(new Error("No Iota is currently connected")); - }); - }, - ); - const [, state] = await Promise.all([ - withDeadline( - client.auth(), - syncTimeoutMs, - "MTP authentication timed out", - signal, - ), - stateSync, - ]); - if (state.type.startsWith("Error")) { - throw new Error(`State synchronization failed: ${state.type}`); - } - const acknowledgement = normalizeMtpMessage( - await withDeadline( - requestWithId(client, ids, "ClientStateAck", { - SessionId: state.data.SessionId, - VersionNumber: state.data.VersionNumber, - }), - ackTimeoutMs, - "State acknowledgement timed out", - signal, - ), - ); - if (acknowledgement.type.startsWith("Error")) { - throw new Error(`State acknowledgement failed: ${acknowledgement.type}`); - } - if (signal.aborted) throw abortError(signal); - return state; -} - -function useMessageHandlers() { - const interceptorsRef = useRef(new Set()); - const pushHandlersRef = useRef(new Set()); - const lastInitialStateRef = useRef(null); - const subscribePush = useCallback((handler: PushHandler) => { - pushHandlersRef.current.add(handler); - const initialState = lastInitialStateRef.current; - if (initialState?.type === "GetStates") { - void Promise.resolve(handler(initialState)).catch(() => undefined); - } - return () => pushHandlersRef.current.delete(handler); - }, []); - const addInterceptor = useCallback((interceptor: MTPInterceptor) => { - interceptorsRef.current.add(interceptor); - return () => interceptorsRef.current.delete(interceptor); - }, []); - return { - addInterceptor, - interceptorsRef, - lastInitialStateRef, - pushHandlersRef, - subscribePush, - }; -} - -function BrowserProvider(props: { - children: ReactNode; - blockConnection?: boolean; -}) { - const { load } = useStorage(); - - const [readyState, setReadyState] = useState( - ConnectionState.Disconnected, - ); - const [identified, setIdentified] = useState(false); - const [identifying, setIdentifying] = useState(false); - - const [freshCommunities, setFreshCommunities] = useState([]); - const [freshContacts, setFreshContacts] = useState([]); - const [freshCalls, setFreshCalls] = useState([]); - - const clientRef = useRef> | null>( - null, - ); - const requestIdsRef = useRef(null); - const { - addInterceptor, - interceptorsRef, - lastInitialStateRef, - pushHandlersRef, - subscribePush, - } = useMessageHandlers(); - - const connected = readyState === ConnectionState.Connected; - - // MTP url - const [mtpUrl, setMtpUrl] = useState(null); - useEffect(() => { - load("omega_url").then(setMtpUrl); - }, [load]); - - // Validation override functions - const send: BoundSendFn = useMemo( - () => async (type, data) => { - const client = clientRef.current; - const ids = requestIdsRef.current; - - if (!client) { - throw new Error("mtp is not connected"); - } - if (!ids) { - throw new Error("MTP request allocator is unavailable"); - } - - const rawMessage = await requestWithId( - client, - ids, - type, - (data ?? {}) as Record, - ); - const response = validateResponse(type, normalizeMtpMessage(rawMessage)); - setFreshContacts((contacts) => removeMissingContacts(contacts, response)); - if (response.type.startsWith("Error")) { - const errorData = response.data as Record; - throw new ProtocolError({ - type: response.type, - requestId: response.id, - errorType: - typeof errorData.ErrorType === "string" - ? errorData.ErrorType - : undefined, - }); - } - return response; - }, - [], - ); - - const subscribe = useCallback((type, handler) => { - const client = clientRef.current; - if (!client) { - return () => {}; - } - - return client.subscribe(type, (message) => { - handler(validateResponse(type, normalizeMtpMessage(message))); - }); - }, []); - - // Reconnect stuff - const resolveConnectionRef = useRef(() => {}); - useEffect(() => { - if (!mtpUrl) return; - - let attempts = 0; - let reconnectTimer: ReturnType | null = null; - let reconnectResetTimer: ReturnType | null = null; - let reconnectScheduled = false; - let disposed = false; - let connectionGeneration = 0; - - const clearReconnectTimer = () => { - if (!reconnectTimer) return; - clearTimeout(reconnectTimer); - reconnectTimer = null; - reconnectScheduled = false; - }; - - const clearReconnectResetTimer = () => { - if (!reconnectResetTimer) return; - clearTimeout(reconnectResetTimer); - reconnectResetTimer = null; - }; - - const scheduleReconnect = (error: unknown) => { - if (disposed || reconnectScheduled) return; - attempts += 1; - const shortRetry = attempts <= RECONNECT_TRIES; - if (!shortRetry) { - log(0, "mtp", "red", "Reconnection attempts exhausted", error); - sonnerToast.error("Connection failed", { - id: "mtp-connection-toast", - description: - error instanceof Error - ? `${error.message.split(":")[0]}. Retrying in the background.` - : "Connection lost. Retrying in the background.", - icon: null, - duration: Infinity, - closeButton: true, - promise: null, - } as unknown as Parameters[1]); - } else { - sonnerToast.loading( - `Reconnecting to server... (attempt ${attempts} of ${RECONNECT_TRIES})`, - { id: "mtp-connection-toast" }, - ); - } - - const baseDelay = shortRetry ? RETRY_INTERVAL : RECONNECT_LONG_INTERVAL; - const jitter = 1 + (Math.random() * 2 - 1) * RECONNECT_JITTER; - reconnectScheduled = true; - reconnectTimer = setTimeout( - () => { - reconnectScheduled = false; - reconnectTimer = null; - void connect(); - }, - Math.round(baseDelay * jitter), - ); - }; - - async function connect() { - if (disposed || props.blockConnection) return; - - const generation = ++connectionGeneration; - let client: Awaited> | null = null; - let failed = false; - let connectionReady = false; - const attemptAbort = new AbortController(); - const cleanup = () => { - attemptAbort.abort( - new Error("Initial state synchronization was cancelled"), - ); - client?.disconnect(); - if (clientRef.current === client) { - clientRef.current = null; - requestIdsRef.current = null; - } - clearReconnectResetTimer(); - if (generation === connectionGeneration) { - setReadyState(ConnectionState.Disconnected); - setIdentified(false); - setIdentifying(false); - } - }; - try { - setIdentified(false); - setIdentifying(false); - - const [userId, keyring] = await Promise.all([ - load("user_id"), - load("mtp_keyring"), - ]); - if (!userId || !keyring) { - throw new Error("Missing login credentials"); - } - const forcedOmikronUrl = await load("forced_omikron_url"); - const forcedOmikronPublicKey = await load("forced_omikron_public_key"); - - let url = null; - let omikronPublicKey = null; - if (forcedOmikronUrl && forcedOmikronPublicKey) { - url = forcedOmikronUrl; - omikronPublicKey = forcedOmikronPublicKey; - } else { - log(2, "mtp", "purple", "Fetching Omikron data."); - const data = await fetch(`${mtpUrl}api/get/omikron/${userId}`, { - signal: AbortSignal.any([ - attemptAbort.signal, - AbortSignal.timeout(DISCOVERY_TIMEOUT), - ]), - }); - - if (data.status === 404) { - throw new Error("No Omikron assignment is currently available"); - } - if (!data.ok) { - throw new Error(`Omikron discovery failed: HTTP ${data.status}`); - } - const omikronData = (await data.json()) as { - id: number; - ip_address: string; - port: number; - public_key: string; - status: string; - }; - - if ( - !omikronData.ip_address || - !omikronData.port || - !omikronData.public_key - ) - throw new Error("Invalid Omikron data"); - - url = `https://${omikronData.ip_address}:${omikronData.port}`; - omikronPublicKey = omikronData.public_key; - } - //codec.decode(new Uint8Array(await res.arrayBuffer())), - - if (!url || !omikronPublicKey) - throw new Error("Missing Omikron URL or Public Key"); - - log(2, "mtp", "green", "Connecting to: " + url); - - client = await MTPClient.create({ - url, - credentials: { - clientId: userId, - keyring: base64ToUint8Array(keyring), - }, - hostPublicKey: { - value: omikronPublicKey, - encoding: "base64", - }, - descriptor: "client", - pings: true, - logger: (event) => { - if (event.type === "state") { - if (generation !== connectionGeneration) return; - const state = client?.state ?? ConnectionState.Disconnected; - setReadyState(state); - if ( - state === ConnectionState.Disconnected && - clientRef.current === client && - !failed - ) { - failed = true; - const error = new Error("MTP connection lost"); - attemptAbort.abort(error); - if (connectionReady) { - cleanup(); - scheduleReconnect(error); - } - } - } - - if (event.type !== "Pong" && event.type !== "Ping") { - log( - 2, - "mtp", - event.type === "state" - ? "purple" - : event.direction === "recv" - ? "cyan" - : event.direction === "send" - ? "gray" - : "blue", - event.type === "state" - ? event.data - : event.direction === "recv" - ? "< " + event.type - : event.direction === "send" - ? "> " + event.type - : event.type, - event, - ); - } - }, - }); - - if (disposed || generation !== connectionGeneration) { - client.disconnect(); - return; - } - const activeClient = client; - - clientRef.current = activeClient; - requestIdsRef.current = new RequestIdAllocator(); - for (const type of PUSH_TYPES) { - activeClient.subscribe(type, (message) => { - let validated: ProtocolMessage; - try { - validated = validateResponse(type, normalizeMtpMessage(message)); - } catch (error) { - log(1, "mtp", "red", "Failed to validate push message", error, { - type, - data: message.data, - }); - return; - } - - setFreshContacts((contacts) => - removeMissingContacts(contacts, validated), - ); - for (const handler of [...pushHandlersRef.current]) { - void Promise.resolve() - .then(() => handler(validated)) - .catch((error) => { - log(1, "mtp", "red", "Push handler failed", error, { type }); - }); - } - if (validated.type === "GetStates") { - lastInitialStateRef.current = validated; - } - if ( - validated.type === "ErrorNoIota" && - clientRef.current === activeClient && - !failed - ) { - failed = true; - const error = new Error("No Iota is currently connected"); - attemptAbort.abort(error); - cleanup(); - scheduleReconnect(error); - } - }); - } - setReadyState(activeClient.state); - setIdentifying(true); - - const ids = requestIdsRef.current; - if (!ids) throw new Error("MTP request allocator is unavailable"); - const finalResponse = await completeInitialSynchronization( - activeClient, - ids, - attemptAbort.signal, - ); - - if (disposed || clientRef.current !== activeClient) return; - - setFreshContacts(finalResponse.data.Contacts); - setFreshCommunities(finalResponse.data.Communities); - setFreshCalls(finalResponse.data.Calls); - connectionReady = true; - setIdentifying(false); - setIdentified(true); - - clearReconnectTimer(); - clearReconnectResetTimer(); - reconnectResetTimer = setTimeout(() => { - attempts = 0; - reconnectResetTimer = null; - }, RECONNECT_RESET * 1_000); - resolveConnectionRef.current?.(); - } catch (connectError) { - if (disposed || generation !== connectionGeneration) { - client?.disconnect(); - return; - } - failed = true; - cleanup(); - const connectErrorMessage = - connectError instanceof Error - ? connectError.message - : String(connectError ?? "Unknown error"); - log( - 0, - "mtp", - "red", - `Connection/authentication attempt failed: ${connectErrorMessage}`, - getProtocolErrorDetails(connectError) ?? connectError, - ); - - scheduleReconnect(connectError); - } - } - - void connect(); - - return () => { - disposed = true; - clearReconnectTimer(); - clearReconnectResetTimer(); - - clientRef.current?.disconnect(); - clientRef.current = null; - requestIdsRef.current = null; - setReadyState(ConnectionState.Disconnected); - setIdentified(false); - setIdentifying(false); - sonnerToast.dismiss("mtp-connection-toast"); - }; - }, [ - lastInitialStateRef, - mtpUrl, - props.blockConnection, - load, - pushHandlersRef, - ]); - - // No Iota check - useEffect(() => { - if (!connected) return; - - return subscribe("ErrorNoIota", () => { - setIdentified(false); - setIdentifying(false); - sonnerToast.error("We couldn't reach your Iota", { - description: - "Check your network connection and try restarting your Iota", - icon: null, - duration: Infinity, - closeButton: true, - }); - resolveConnectionRef.current?.(); - }); - }, [connected, subscribe]); - - // Async queue - const loadingDescription = useMemo(() => { - if (!mtpUrl) return "Loading connection details"; - if (readyState === ConnectionState.Connecting || !connected) { - return "Establishing transport channel"; - } - if (identifying || !identified) return "Waiting for authenticated session"; - return "Loading..."; - }, [connected, identified, identifying, readyState, mtpUrl]); - const contextReady = connected && identified && mtpUrl !== null; - const mtpRef = useMemo( - () => - createAsyncQueue<{ - send: typeof send; - subscribe: typeof subscribe; - subscribePush: typeof subscribePush; - }>(), - [], - ); - useEffect(() => { - if (connected && identified && mtpUrl) { - mtpRef.set({ - send, - subscribe, - subscribePush, - }); - } - }, [connected, identified, mtpUrl, send, subscribe, subscribePush, mtpRef]); - - const sendQueued: BoundSendFn = useMemo( - () => async (type, data) => { - const mtp = await mtpRef.get(); - const response = await mtp.send(type, data); - for (const interceptor of interceptorsRef.current) { - void Promise.resolve( - interceptor({ type, data, response: response as ProtocolMessage }), - ).catch((error) => { - log(1, "mtp", "yellow", "MTP interceptor failed", error, { type }); - }); - } - return response; - }, - [interceptorsRef, mtpRef], - ); - - return ( - - {props.children} - - ); -} - -type NativeSnapshot = { - generation: number; - readyState: number; - identified: boolean; - state?: unknown; - error?: string; -}; - -function TauriProvider(props: { - children: ReactNode; - blockConnection?: boolean; -}) { - const [snapshot, setSnapshot] = useState({ - generation: 0, - readyState: ConnectionState.Disconnected, - identified: false, - }); - const [freshContacts, setFreshContacts] = useState([]); - const [freshCommunities, setFreshCommunities] = useState([]); - const [freshCalls, setFreshCalls] = useState([]); - const generationRef = useRef(0); - const { - addInterceptor, - interceptorsRef, - lastInitialStateRef, - pushHandlersRef, - subscribePush, - } = useMessageHandlers(); - const subscriptionsRef = useRef( - new Map void>>(), - ); - - const applySnapshot = useCallback((next: NativeSnapshot) => { - if (next.generation < generationRef.current) return; - generationRef.current = next.generation; - if (next.error) { - log(0, "android", "orange", "MTP connection failed", next.error); - } - if (!next.identified) { - setSnapshot(next); - return; - } - if (next.state === undefined) { - setSnapshot({ - ...next, - identified: false, - error: "Native MTP connection omitted initial state", - }); - return; - } - const parsed = schemas.ClientStateSync.response.safeParse(next.state); - if (!parsed.success) { - log(0, "mtp", "red", "Invalid native MTP state", parsed.error); - setSnapshot({ - ...next, - identified: false, - error: "Invalid ClientStateSync payload", - }); - return; - } - setFreshContacts(parsed.data.Contacts); - setFreshCommunities(parsed.data.Communities); - setFreshCalls(parsed.data.Calls); - setSnapshot(next); - }, []); - - const dispatchMessage = useCallback( - (raw: unknown) => { - if (!raw || typeof raw !== "object" || !("type" in raw)) return; - const message = raw as { id?: number; type: string; data: unknown }; - let validated: ProtocolMessage; - try { - validated = validateResponse( - message.type as keyof Schemas & string, - normalizeMtpMessage(message), - ); - } catch (error) { - log(1, "mtp", "red", "Failed to validate native MTP message", error); - return; - } - for (const handler of subscriptionsRef.current.get(validated.type) ?? - []) { - handler(validated); - } - if (!isPushType(validated.type)) return; - setFreshContacts((contacts) => - removeMissingContacts(contacts, validated), - ); - for (const handler of [...pushHandlersRef.current]) { - void Promise.resolve(handler(validated)).catch((error) => { - log(1, "mtp", "red", "Native MTP push handler failed", error, { - type: validated.type, - }); - }); - } - if (validated.type === "GetStates") { - lastInitialStateRef.current = validated; - } - }, - [lastInitialStateRef, pushHandlersRef], - ); - - useEffect(() => { - if (props.blockConnection) return; - let disposed = false; - let unlisten: UnlistenFn | undefined; - void (async () => { - try { - const nextUnlisten = await listen< - | { kind: "state"; snapshot: NativeSnapshot } - | { kind: "message"; generation: number; message: unknown } - | { - kind: "log"; - level: number; - message: string; - details?: unknown; - } - >("mtp://event", ({ payload }) => { - if (disposed) return; - if (payload.kind === "state") { - applySnapshot(payload.snapshot); - return; - } - if (payload.kind === "message") { - if (payload.generation === generationRef.current) { - dispatchMessage(payload.message); - } - return; - } - log( - payload.level, - "android", - "orange", - payload.message, - payload.details, - ); - }); - if (disposed) nextUnlisten(); - else unlisten = nextUnlisten; - } catch (error) { - log(0, "mtp", "red", "Failed to subscribe to native MTP events", error); - } - - try { - const current = await invoke("mtp_status"); - if (!disposed) applySnapshot(current); - } catch (error) { - log(0, "mtp", "red", "Failed to load native MTP status", error); - } - })(); - return () => { - disposed = true; - unlisten?.(); - }; - }, [applySnapshot, dispatchMessage, props.blockConnection]); - - useEffect(() => { - if (props.blockConnection) return; - const updateVisibility = () => { - void invoke("mtp_set_ui_visible", { - visible: document.visibilityState === "visible" && document.hasFocus(), - }); - }; - updateVisibility(); - document.addEventListener("visibilitychange", updateVisibility); - window.addEventListener("focus", updateVisibility); - window.addEventListener("blur", updateVisibility); - return () => { - document.removeEventListener("visibilitychange", updateVisibility); - window.removeEventListener("focus", updateVisibility); - window.removeEventListener("blur", updateVisibility); - void invoke("mtp_set_ui_visible", { visible: false }); - }; - }, [props.blockConnection]); - - const send = useCallback( - async (type, data) => { - const response = await invoke("mtp_request", { - typeName: type, - data: data ?? {}, - }); - const validated = validateResponse(type, normalizeMtpMessage(response)); - setFreshContacts((contacts) => - removeMissingContacts(contacts, validated), - ); - if (validated.type.startsWith("Error")) { - const errorData = validated.data as Record; - throw new ProtocolError({ - type: validated.type, - requestId: validated.id, - errorType: - typeof errorData.ErrorType === "string" - ? errorData.ErrorType - : undefined, - }); - } - for (const interceptor of interceptorsRef.current) { - void Promise.resolve( - interceptor({ type, data, response: validated as ProtocolMessage }), - ).catch((error) => { - log(1, "mtp", "yellow", "MTP interceptor failed", error, { type }); - }); - } - return validated; - }, - [interceptorsRef], - ); - - const subscribe = useCallback((type, handler) => { - const handlers = - subscriptionsRef.current.get(type) ?? - new Set<(message: ProtocolMessage) => void>(); - handlers.add(handler as (message: ProtocolMessage) => void); - subscriptionsRef.current.set(type, handlers); - return () => { - handlers.delete(handler as (message: ProtocolMessage) => void); - if (handlers.size === 0) subscriptionsRef.current.delete(type); - }; - }, []); - const connected = snapshot.readyState === ConnectionState.Connected; - const contextReady = connected && snapshot.identified; - - return ( - - {props.children} - - ); -} +import { BrowserProvider } from "./browser"; +import { MTPContext, type MTPContextType } from "./mtpContext"; +import { TauriProvider } from "./tauri"; export function Provider(props: { children: ReactNode; blockConnection?: boolean; +}) { + if (isTauri()) return ; + return ; +} + +function BrowserWasmProvider(props: { + children: ReactNode; + blockConnection?: boolean; }) { const [wasmReady, setWasmReady] = useState(false); const [wasmError, setWasmError] = useState(); - useEffect(() => { let active = true; void MTPClient.init().then( - () => { - if (active) setWasmReady(true); - }, - (error: unknown) => { - if (active) setWasmError(() => error); - }, + () => active && setWasmReady(true), + (error: unknown) => active && setWasmError(() => error), ); return () => { active = false; }; }, []); - if (wasmError) throw wasmError; - if (!wasmReady) return null; - - return isTauri() ? ( - - ) : ( - - ); + return wasmReady ? : null; } -export function useMTP(): ContextType { +export function useMTP(): MTPContextType { const context = useContext(MTPContext); - if (!context) { - throw new Error("useMTP must be used within an MTPProvider"); - } + if (!context) throw new Error("useMTP must be used within an MTPProvider"); return context; } diff --git a/packages/mtp/src/index.ts b/packages/mtp/src/index.ts index 19f5acd..a4f05c8 100644 --- a/packages/mtp/src/index.ts +++ b/packages/mtp/src/index.ts @@ -1,9 +1,7 @@ export { Provider, useMTP } from "./context"; -export { RequestIdAllocator } from "./requestIds"; export type { BoundSendFn, MTPExchange, MTPInterceptor, - PushHandler, ProtocolMessage, -} from "./context"; +} from "./mtpContext"; diff --git a/packages/mtp/src/mtpContext.tsx b/packages/mtp/src/mtpContext.tsx new file mode 100644 index 0000000..1f1654d --- /dev/null +++ b/packages/mtp/src/mtpContext.tsx @@ -0,0 +1,159 @@ +import { createContext, useCallback, useRef } from "react"; +import type { + MTPRequestFunction, + MTPResponseFrame, + MTPSubscriptionFunction, +} from "mtp"; +import { + mtp as mtpSchemas, + type Calls, + type Communities, + type Contacts, +} from "@tensamin/shared/data"; +import { log } from "@tensamin/shared/log"; + +export type ProtocolMessage< + Type extends keyof typeof mtpSchemas & string = keyof typeof mtpSchemas & + string, +> = MTPResponseFrame; + +export type BoundSendFn = MTPRequestFunction; + +export type MTPExchange = { + type: keyof typeof mtpSchemas & string; + data: unknown; + response: ProtocolMessage; +}; + +export type MTPInterceptor = (exchange: MTPExchange) => void | Promise; + +export type MTPContextType = { + send: BoundSendFn; + subscribe: MTPSubscriptionFunction; + addInterceptor: (interceptor: MTPInterceptor) => () => void; + readyState: number; + identified: boolean; + freshContacts: Contacts; + freshCommunities: Communities; + freshCalls: Calls; + contextReady: boolean; + loadingDescription: string; +}; + +export const MTPContext = createContext(undefined); + +export function removeMissingContacts( + contacts: Contacts, + message: ProtocolMessage<"GetStates">, +): Contacts { + const missing = new Set(message.data.MissingUserIds ?? []); + return contacts.filter((contact) => !missing.has(contact.UserId)); +} + +export function useMessageHandlers() { + const interceptorsRef = useRef(new Set()); + const subscriptionHandlersRef = useRef( + new Map void | Promise>>(), + ); + const transportRef = useRef<{ + subscribe: MTPSubscriptionFunction; + } | null>(null); + const transportGenerationRef = useRef(0); + const transportUnsubscribersRef = useRef(new Map void>()); + const lastInitialStateRef = useRef | null>(null); + + const attachType = useCallback( + (type: Type) => { + const transport = transportRef.current; + if (!transport || transportUnsubscribersRef.current.has(type)) return; + const generation = transportGenerationRef.current; + const unsubscribe = transport.subscribe(type, (message) => { + if ( + transportRef.current !== transport || + transportGenerationRef.current !== generation + ) + return; + if (type === "GetStates") { + lastInitialStateRef.current = message as ProtocolMessage<"GetStates">; + } + for (const handler of [ + ...(subscriptionHandlersRef.current.get(type) ?? []), + ]) { + void Promise.resolve(handler(message as ProtocolMessage)).catch( + (error) => { + log(1, "mtp", "red", "Subscription handler failed", error, { + type, + }); + }, + ); + } + }); + transportUnsubscribersRef.current.set(type, unsubscribe); + }, + [], + ); + + const attachSubscriptions = useCallback( + (transport: { subscribe: MTPSubscriptionFunction }) => { + for (const unsubscribe of transportUnsubscribersRef.current.values()) { + unsubscribe(); + } + transportUnsubscribersRef.current.clear(); + transportRef.current = transport; + const generation = ++transportGenerationRef.current; + for (const type of subscriptionHandlersRef.current.keys()) { + attachType(type as keyof typeof mtpSchemas & string); + } + return () => { + if ( + transportRef.current !== transport || + transportGenerationRef.current !== generation + ) + return; + transportRef.current = null; + transportGenerationRef.current += 1; + for (const unsubscribe of transportUnsubscribersRef.current.values()) { + unsubscribe(); + } + transportUnsubscribersRef.current.clear(); + }; + }, + [attachType], + ); + + const subscribe = useCallback>( + (type, handler) => { + const handlers = subscriptionHandlersRef.current.get(type) ?? new Set(); + const untypedHandler = handler as ( + message: ProtocolMessage, + ) => void | Promise; + handlers.add(untypedHandler); + subscriptionHandlersRef.current.set(type, handlers); + attachType(type); + const initialState = lastInitialStateRef.current; + if (type === "GetStates" && initialState) { + void Promise.resolve(untypedHandler(initialState)).catch( + () => undefined, + ); + } + return () => { + handlers.delete(untypedHandler); + if (handlers.size !== 0) return; + subscriptionHandlersRef.current.delete(type); + transportUnsubscribersRef.current.get(type)?.(); + transportUnsubscribersRef.current.delete(type); + }; + }, + [attachType], + ); + const addInterceptor = useCallback((interceptor: MTPInterceptor) => { + interceptorsRef.current.add(interceptor); + return () => interceptorsRef.current.delete(interceptor); + }, []); + return { + addInterceptor, + attachSubscriptions, + interceptorsRef, + subscribe, + }; +} diff --git a/packages/mtp/src/protocolFields.test.ts b/packages/mtp/src/protocolFields.test.ts deleted file mode 100644 index ef0c18f..0000000 --- a/packages/mtp/src/protocolFields.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { fromWireData, toWireData } from "./protocolFields"; - -describe("MTP protocol field translation", () => { - it("maps application message fields to MTP wire fields", () => { - expect( - toWireData({ - Messages: [{ Content: "abc", MessageId: 4 }], - }), - ).toEqual({ - Messages: [{ AppContent: "abc", AppMessageId: 4 }], - }); - }); - - it("maps MTP wire fields back to application fields", () => { - expect( - fromWireData({ - AppCreatedAt: 123, - Message: { AppContent: "abc", AppMessageId: 4 }, - }), - ).toEqual({ - CreatedAt: 123, - Message: { Content: "abc", MessageId: 4 }, - }); - }); - - it("preserves byte arrays and unrelated fields", () => { - const bytes = new Uint8Array([1, 2, 3]); - const translated = toWireData({ Payload: bytes, Other: "value" }) as { - Payload: Uint8Array; - Other: string; - }; - - expect(translated.Payload).toBe(bytes); - expect(translated.Other).toBe("value"); - }); - - it("rejects field mapping collisions", () => { - expect(() => toWireData({ Content: "a", AppContent: "b" })).toThrow( - "MTP field translation collision", - ); - }); -}); diff --git a/packages/mtp/src/protocolFields.ts b/packages/mtp/src/protocolFields.ts deleted file mode 100644 index 3ec3d5d..0000000 --- a/packages/mtp/src/protocolFields.ts +++ /dev/null @@ -1,58 +0,0 @@ -const APPLICATION_TO_WIRE_FIELDS = { - Content: "AppContent", - CreatedAt: "AppCreatedAt", - MessageId: "AppMessageId", -} as const; - -const WIRE_TO_APPLICATION_FIELDS = { - AppContent: "Content", - AppCreatedAt: "CreatedAt", - AppMessageId: "MessageId", -} as const; - -function mapProtocolFields( - value: unknown, - fieldMap: Readonly>, -): unknown { - if ( - value === null || - typeof value !== "object" || - value instanceof Uint8Array - ) { - return value; - } - - if (Array.isArray(value)) { - return value.map((item) => mapProtocolFields(item, fieldMap)); - } - - const source = value as Record; - const target: Record = {}; - - for (const [key, child] of Object.entries(source)) { - const mappedKey = fieldMap[key] ?? key; - - if (mappedKey in target) { - throw new Error(`MTP field translation collision for ${mappedKey}`); - } - - target[mappedKey] = mapProtocolFields(child, fieldMap); - } - - return target; -} - -export function toWireData(value: unknown): unknown { - return mapProtocolFields(value, APPLICATION_TO_WIRE_FIELDS); -} - -export function fromWireData(value: unknown): unknown { - return mapProtocolFields(value, WIRE_TO_APPLICATION_FIELDS); -} - -export function fromWireMessage(message: T): T { - return { - ...message, - data: fromWireData(message.data), - }; -} diff --git a/packages/mtp/src/requestIds.test.ts b/packages/mtp/src/requestIds.test.ts deleted file mode 100644 index 82fd508..0000000 --- a/packages/mtp/src/requestIds.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { RequestIdAllocator } from "./requestIds"; - -describe("MTP request ID allocation", () => { - it("allocates nonzero request IDs monotonically", () => { - const ids = new RequestIdAllocator(); - - expect(ids.allocate()).toBe(1); - expect(ids.allocate()).toBe(2); - expect(new RequestIdAllocator().allocate()).toBe(1); - }); - - it("does not wrap exhausted request IDs", () => { - const ids = new RequestIdAllocator(0x1_0000_0000); - - expect(() => ids.allocate()).toThrow("MTP request ID space exhausted"); - }); - - it("rejects invalid allocator states", () => { - expect(() => new RequestIdAllocator(0)).toThrow( - "invalid MTP request ID allocator state", - ); - }); -}); diff --git a/packages/mtp/src/requestIds.ts b/packages/mtp/src/requestIds.ts deleted file mode 100644 index 5581e8a..0000000 --- a/packages/mtp/src/requestIds.ts +++ /dev/null @@ -1,24 +0,0 @@ -const MAX_MTP_REQUEST_ID = 0xffff_ffff; - -export class RequestIdAllocator { - #next: number; - - constructor(next = 1) { - if ( - !Number.isSafeInteger(next) || - next <= 0 || - next > MAX_MTP_REQUEST_ID + 1 - ) { - throw new RangeError("invalid MTP request ID allocator state"); - } - this.#next = next; - } - - allocate(): number { - if (this.#next > MAX_MTP_REQUEST_ID) { - throw new Error("MTP request ID space exhausted for this connection"); - } - - return this.#next++; - } -} diff --git a/packages/mtp/src/tauri.tsx b/packages/mtp/src/tauri.tsx new file mode 100644 index 0000000..92ac209 --- /dev/null +++ b/packages/mtp/src/tauri.tsx @@ -0,0 +1,258 @@ +import { + type ReactNode, + useCallback, + useEffect, + useRef, + useState, +} from "react"; +import { invoke } from "@tauri-apps/api/core"; +import { listen, type UnlistenFn } from "@tauri-apps/api/event"; +import { + ConnectionState, + MTPProxyConnection, + type MTPFrame, + type MTPProxyAdapter, +} from "mtp"; +import { + mtp as mtpSchemas, + type Calls, + type Communities, + type Contacts, +} from "@tensamin/shared/data"; +import { log } from "@tensamin/shared/log"; + +import { + type BoundSendFn, + MTPContext, + type ProtocolMessage, + removeMissingContacts, + useMessageHandlers, +} from "./mtpContext"; + +type NativeSnapshot = { + generation: number; + readyState: number; + identified: boolean; + state?: unknown; + error?: string; +}; + +function createTauriAdapter() { + const subscriptions = new Map void>>(); + const adapter: MTPProxyAdapter = { + request: (type, data) => + invoke("mtp_request", { typeName: type, data }), + subscribe(type, handler) { + const handlers = subscriptions.get(type) ?? new Set(); + handlers.add(handler); + subscriptions.set(type, handlers); + return () => { + handlers.delete(handler); + if (handlers.size === 0) subscriptions.delete(type); + }; + }, + }; + return { + adapter, + dispatch(message: MTPFrame) { + for (const handler of subscriptions.get(message.type) ?? []) + handler(message); + }, + }; +} + +export function TauriProvider(props: { + children: ReactNode; + blockConnection?: boolean; +}) { + const [snapshot, setSnapshot] = useState({ + generation: 0, + readyState: ConnectionState.Disconnected, + identified: false, + }); + const [freshContacts, setFreshContacts] = useState([]); + const [freshCommunities, setFreshCommunities] = useState([]); + const [freshCalls, setFreshCalls] = useState([]); + const generationRef = useRef(0); + const { addInterceptor, attachSubscriptions, interceptorsRef, subscribe } = + useMessageHandlers(); + const [{ bridge, connection }] = useState(() => { + const bridge = createTauriAdapter(); + return { + bridge, + connection: new MTPProxyConnection(bridge.adapter, { + schemas: mtpSchemas, + throwProtocolErrors: true, + onValidationError: (error) => { + log(1, "mtp", "red", "Failed to validate native MTP message", error); + }, + }), + }; + }); + + const applySnapshot = useCallback(async (next: NativeSnapshot) => { + if (next.generation < generationRef.current) return; + generationRef.current = next.generation; + if (next.error) + log(0, "android", "orange", "MTP connection failed", next.error); + if (!next.identified) { + setSnapshot(next); + return; + } + if (next.state === undefined) { + setSnapshot({ + ...next, + identified: false, + error: "Native MTP connection omitted initial state", + }); + return; + } + try { + const state = await mtpSchemas.ClientStateSync.response.parseAsync( + next.state, + ); + setFreshContacts(state.Contacts); + setFreshCommunities(state.Communities); + setFreshCalls(state.Calls); + setSnapshot(next); + } catch (error) { + log(0, "mtp", "red", "Invalid native MTP state", error); + setSnapshot({ + ...next, + identified: false, + error: "Invalid ClientStateSync payload", + }); + } + }, []); + + const dispatchMessage = useCallback( + (message: MTPFrame) => { + bridge.dispatch(message); + }, + [bridge], + ); + + useEffect(() => { + return attachSubscriptions(connection); + }, [attachSubscriptions, connection]); + + useEffect( + () => + subscribe("GetStates", (message) => { + setFreshContacts((contacts) => + removeMissingContacts(contacts, message), + ); + }), + [subscribe], + ); + + useEffect(() => { + if (props.blockConnection) return; + let disposed = false; + let unlisten: UnlistenFn | undefined; + void (async () => { + try { + const nextUnlisten = await listen< + | { kind: "state"; snapshot: NativeSnapshot } + | { kind: "message"; generation: number; message: MTPFrame } + | { kind: "log"; level: number; message: string; details?: unknown } + >("mtp://event", ({ payload }) => { + if (disposed) return; + if (payload.kind === "state") { + void applySnapshot(payload.snapshot); + } else if (payload.kind === "message") { + if (payload.generation === generationRef.current) { + dispatchMessage(payload.message); + } + } else { + log( + payload.level, + "android", + "orange", + payload.message, + payload.details, + ); + } + }); + if (disposed) nextUnlisten(); + else unlisten = nextUnlisten; + } catch (error) { + log(0, "mtp", "red", "Failed to subscribe to native MTP events", error); + } + try { + const current = await invoke("mtp_status"); + if (!disposed) await applySnapshot(current); + } catch (error) { + log(0, "mtp", "red", "Failed to load native MTP status", error); + } + })(); + return () => { + disposed = true; + unlisten?.(); + }; + }, [applySnapshot, dispatchMessage, props.blockConnection]); + + useEffect(() => { + if (props.blockConnection) return; + const updateVisibility = () => { + void invoke("mtp_set_ui_visible", { + visible: document.visibilityState === "visible" && document.hasFocus(), + }); + }; + updateVisibility(); + document.addEventListener("visibilitychange", updateVisibility); + window.addEventListener("focus", updateVisibility); + window.addEventListener("blur", updateVisibility); + return () => { + document.removeEventListener("visibilitychange", updateVisibility); + window.removeEventListener("focus", updateVisibility); + window.removeEventListener("blur", updateVisibility); + void invoke("mtp_set_ui_visible", { visible: false }); + }; + }, [props.blockConnection]); + + const send = useCallback( + async (type, data, options) => { + const response = await connection.request(type, data, options); + if (response.type === "GetStates") { + setFreshContacts((contacts) => + removeMissingContacts( + contacts, + response as ProtocolMessage<"GetStates">, + ), + ); + } + for (const interceptor of interceptorsRef.current) { + void Promise.resolve(interceptor({ type, data, response })).catch( + (error) => { + log(1, "mtp", "yellow", "MTP interceptor failed", error, { type }); + }, + ); + } + return response; + }, + [connection, interceptorsRef], + ); + const connected = snapshot.readyState === ConnectionState.Connected; + + return ( + + {props.children} + + ); +} diff --git a/packages/notifications/src/context.tsx b/packages/notifications/src/context.tsx index 7a8b32a..e0da277 100644 --- a/packages/notifications/src/context.tsx +++ b/packages/notifications/src/context.tsx @@ -16,7 +16,6 @@ import { useLocation, useNavigate } from "@tanstack/react-router"; import { decryptChatText } from "@tensamin/crypto/chatSecret"; import { log } from "@tensamin/shared/log"; import { playSound } from "@tensamin/shared/sounds"; -import { type RawMessage } from "@tensamin/chat/values"; export const context = createContext(undefined); @@ -30,7 +29,7 @@ async function requestNotificationPermission() { } export default function Provider(props: { children: React.ReactNode }) { - const { subscribePush, send } = useMTP(); + const { subscribe, send } = useMTP(); const { load } = useStorage(); const { get } = useUser(); const { addLiveMessage, chatSecret, getChatSecret, userId } = useChat(); @@ -39,148 +38,140 @@ export default function Provider(props: { children: React.ReactNode }) { const location = useLocation(); useEffect(() => { - return subscribePush(async (message) => { - if (message.type === "MessageLive") { - const data = message.data as { - Message?: RawMessage; - SenderId?: number; - }; + return subscribe("MessageLive", async ({ data }) => { + if (!data.SenderId) return; - if (!data.SenderId) return; + const isCurrentChat = + location.pathname === "/chat" && userId === data.SenderId; + const appFocused = + document.hasFocus() && document.visibilityState === "visible"; + const shouldAlert = !isCurrentChat || !appFocused; - const isCurrentChat = - location.pathname === "/chat" && userId === data.SenderId; - const appFocused = - document.hasFocus() && document.visibilityState === "visible"; - const shouldAlert = !isCurrentChat || !appFocused; + const messageSecret = + isCurrentChat && chatSecret + ? chatSecret + : await getChatSecret(data.SenderId); - const messageSecret = - isCurrentChat && chatSecret - ? chatSecret - : await getChatSecret(data.SenderId); + if (!data.Message || !messageSecret) return; + if (shouldAlert) playSound("message"); - if (!data.Message || !messageSecret) return; - if (shouldAlert) playSound("message"); + void decryptChatText(messageSecret, data.Message.Content) + .catch((err) => { + log(1, "chat", "red", "Failed to decrypt live message", err, { + SendTime: data.Message?.SendTime, + }); + return null; + }) + .then(async (content) => { + if (!data.Message || !content || !data.SenderId) return; - void decryptChatText(messageSecret, data.Message.Content) - .catch((err) => { - log(1, "chat", "red", "Failed to decrypt live message", err, { - SendTime: data.Message?.SendTime, + if (isCurrentChat) { + addLiveMessage({ + ...data.Message, + Content: content ?? "Failed to decrypt message", + decryptionFailed: content === null, }); - return null; - }) - .then(async (content) => { - if (!data.Message || !content || !data.SenderId) return; + } - if (isCurrentChat) { - addLiveMessage({ - ...data.Message, - Content: content ?? "Failed to decrypt message", - decryptionFailed: content === null, + if (!shouldAlert) return; + + if (!isCurrentChat) { + // todo: add notification symbol to conversation cards (incl. message start) + moveUserIdToTop(data.SenderId); + + if (await load("settings.receive_confirmations")) { + void send("MessageState", { + MessageState: "received", }); } + } - if (!shouldAlert) return; + const user = await get(data.SenderId, [ + "UserId", + "Display", + "Avatar", + ]); - if (!isCurrentChat) { - // todo: add notification symbol to conversation cards (incl. message start) - moveUserIdToTop(data.SenderId); + if (isTauri()) { + if (!appFocused) return; + const permissionGranted = + (await isTauriNotificationPermissionGranted()) || + (await requestTauriNotificationPermission()) === "granted"; - if (await load("settings.receive_confirmations")) { - void send("MessageState", { - MessageState: "received", - }); - } - } - - const user = await get(data.SenderId, [ - "UserId", - "Display", - "Avatar", - ]); - - if (isTauri()) { - if (!appFocused) return; - const permissionGranted = - (await isTauriNotificationPermissionGranted()) || - (await requestTauriNotificationPermission()) === "granted"; - - if (permissionGranted) { - let handledNatively = false; - try { - handledNatively = await invoke( - "mtp_post_message_notification", - { - senderId: user.UserId, - sender: user.Display, - body: content, - avatar: user.Avatar, - }, - ); - } catch (error) { - log( - 1, - "notifications", - "red", - "Failed to create native message notification", - error, - ); - } - - if (!handledNatively) { - sendTauriNotification({ title: user.Display, body: content }); - } - } - } else { - const hasPermissions = await requestNotificationPermission(); - - if (hasPermissions) { - const options: NotificationOptions = { - body: content, - icon: user.Avatar || "/icons/icon-192.png", - badge: "/icons/notification-badge.png", - tag: `message-${user.UserId}`, - silent: true, - }; - if ("serviceWorker" in navigator) { - const registration = - await navigator.serviceWorker.getRegistration(); - if (registration) { - await registration.showNotification(user.Display, { - ...options, - data: { url: `/chat?id=${user.UserId}` }, - }); - return; - } - } - const notification = new Notification(user.Display, options); - notification.onclick = () => { - window.focus(); - navigate({ - to: `/chat?id=${user.UserId}`, - }); - notification.close(); - }; - } else { - sonnerToast(user.Display, { - classNames: { - content: "pl-4", + if (permissionGranted) { + let handledNatively = false; + try { + handledNatively = await invoke( + "mtp_post_message_notification", + { + senderId: user.UserId, + sender: user.Display, + body: content, + avatar: user.Avatar, }, - description: content, - icon: ( - - - - {user.Display.slice(0, 2).toUpperCase()} - - - ), - }); + ); + } catch (error) { + log( + 1, + "notifications", + "red", + "Failed to create native message notification", + error, + ); + } + + if (!handledNatively) { + sendTauriNotification({ title: user.Display, body: content }); } } - }); - return; - } + } else { + const hasPermissions = await requestNotificationPermission(); + + if (hasPermissions) { + const options: NotificationOptions = { + body: content, + icon: user.Avatar || "/icons/icon-192.png", + badge: "/icons/notification-badge.png", + tag: `message-${user.UserId}`, + silent: true, + }; + if ("serviceWorker" in navigator) { + const registration = + await navigator.serviceWorker.getRegistration(); + if (registration) { + await registration.showNotification(user.Display, { + ...options, + data: { url: `/chat?id=${user.UserId}` }, + }); + return; + } + } + const notification = new Notification(user.Display, options); + notification.onclick = () => { + window.focus(); + navigate({ + to: `/chat?id=${user.UserId}`, + }); + notification.close(); + }; + } else { + sonnerToast(user.Display, { + classNames: { + content: "pl-4", + }, + description: content, + icon: ( + + + + {user.Display.slice(0, 2).toUpperCase()} + + + ), + }); + } + } + }); }); }, [ addLiveMessage, @@ -191,7 +182,7 @@ export default function Provider(props: { children: React.ReactNode }) { navigate, send, moveUserIdToTop, - subscribePush, + subscribe, getChatSecret, userId, ]); diff --git a/packages/user/src/context.tsx b/packages/user/src/context.tsx index 423661c..8c41aa4 100644 --- a/packages/user/src/context.tsx +++ b/packages/user/src/context.tsx @@ -9,13 +9,12 @@ import { useState, useSyncExternalStore, } from "react"; -import { useMTP, type ProtocolMessage } from "@tensamin/mtp"; +import { useMTP } from "@tensamin/mtp"; import { clientUserStateSchema, mtp as schemas, publicUserStateSchema, - userStateEntrySchema, } from "@tensamin/shared/data"; import type z from "zod"; import { createCache } from "@tensamin/cache"; @@ -89,7 +88,7 @@ export default function UserProvider(props: { children: ReactNode }) { ); const revisionsRef = useRef(new Map>()); - const { send, subscribePush } = useMTP(); + const { send, subscribe: subscribeMTP } = useMTP(); const { load } = useStorage(); const { contacts } = useSession(); const [accountId, setAccountId] = useState(null); @@ -174,39 +173,6 @@ export default function UserProvider(props: { children: ReactNode }) { [publishUser], ); - const handleStatePush = useCallback( - async (message: ProtocolMessage) => { - if (!accountId) return; - const data = message.data as Record; - if (message.type === "GetStates") { - if (Array.isArray(data.MissingUserIds)) { - for (const userId of data.MissingUserIds) { - if (typeof userId === "number") removePresence(userId); - } - } - if (!Array.isArray(data.UserStates)) return; - for (const entry of data.UserStates) { - const parsed = userStateEntrySchema.safeParse(entry); - if (!parsed.success) continue; - if (parsed.data.UserId === accountId) continue; - initialStatesRef.current.set( - parsed.data.UserId, - parsed.data.UserState, - ); - if (applyUserState(parsed.data.UserId, parsed.data.UserState)) { - initialStatesRef.current.delete(parsed.data.UserId); - } - } - return; - } - if (message.type !== "ClientChanged") return; - const parsed = schemas.ClientChanged.response.safeParse(data); - if (!parsed.success) return; - applyUserState(parsed.data.UserId, parsed.data.UserState, true); - }, - [accountId, applyUserState, removePresence], - ); - useEffect(() => { void load("user_id").then((accountId) => { accountIdRef.current = accountId; @@ -223,8 +189,24 @@ export default function UserProvider(props: { children: ReactNode }) { useEffect(() => { if (!accountId) return; - return subscribePush(handleStatePush); - }, [accountId, handleStatePush, subscribePush]); + const unsubscribeStates = subscribeMTP("GetStates", ({ data }) => { + for (const userId of data.MissingUserIds ?? []) removePresence(userId); + for (const entry of data.UserStates) { + if (!entry || entry.UserId === accountId) continue; + initialStatesRef.current.set(entry.UserId, entry.UserState); + if (applyUserState(entry.UserId, entry.UserState)) { + initialStatesRef.current.delete(entry.UserId); + } + } + }); + const unsubscribeChanged = subscribeMTP("ClientChanged", ({ data }) => { + applyUserState(data.UserId, data.UserState, true); + }); + return () => { + unsubscribeStates(); + unsubscribeChanged(); + }; + }, [accountId, applyUserState, removePresence, subscribeMTP]); const loadUser = useCallback( async (userId: number): Promise => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 107149b..83d88ff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: overrides: '@methanium/ui': https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz - mtp: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + mtp: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz importers: @@ -16,8 +16,8 @@ importers: specifier: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz version: https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(emojibase@17.0.0)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)(supports-color@7.2.0)(typescript@6.0.3) mtp: - specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz - version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz sonner: specifier: ^2.0.8 version: 2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -98,8 +98,8 @@ importers: specifier: workspace:* version: link:../../packages/storage mtp: - specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz - version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz react: specifier: ^19.2.8 version: 19.2.8 @@ -290,8 +290,8 @@ importers: specifier: ^17.9.0 version: 17.9.0 mtp: - specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz - version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz typescript: specifier: ~6.0.3 version: 6.0.3 @@ -356,8 +356,8 @@ importers: specifier: ^1.29.0 version: 1.30.0(react@19.2.8) mtp: - specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz - version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz react: specifier: ^19.2.8 version: 19.2.8 @@ -431,8 +431,8 @@ importers: packages/crypto: dependencies: mtp: - specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz - version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz react: specifier: ^19.2.8 version: 19.2.8 @@ -506,9 +506,6 @@ importers: '@tauri-apps/api': specifier: ^2.11.1 version: 2.11.1 - '@tensamin/crypto': - specifier: workspace:* - version: link:../crypto '@tensamin/shared': specifier: workspace:* version: link:../shared @@ -516,17 +513,11 @@ importers: specifier: workspace:* version: link:../storage mtp: - specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz - version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz + specifier: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz + version: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz react: specifier: ^19.2.8 version: 19.2.8 - react-dom: - specifier: ^19.2.8 - version: 19.2.8(react@19.2.8) - zod: - specifier: ^4.4.3 - version: 4.4.3 devDependencies: eslint: specifier: ^10.8.0 @@ -5085,8 +5076,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - mtp@https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz: - resolution: {integrity: sha512-rI+xskgAp93o9EdBO/b7HnA0PZTQQPTYuF4Snon/hTvayN+x9O40oad4n/ZUF0ahS6grw00MPKPe89Mfe3BHnw==, tarball: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz} + mtp@https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz: + resolution: {integrity: sha512-MzqeWSaS2lVoiK0coNfY8EPgGNk7QYFS3eRqVYeYBCT0NNm2lQ7T8lLjBuIuMZ6Zh2KAVWhwI2xQIkMdZ7QThA==, tarball: https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz} version: 0.3.0 nanoid@3.3.18: @@ -11337,7 +11328,7 @@ snapshots: ms@2.1.3: {} - mtp@https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz: + mtp@https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz: dependencies: yaml: 2.9.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f713a2d..6ec3531 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -7,4 +7,4 @@ allowBuilds: esbuild: true overrides: "@methanium/ui": "https://git.methanium.net/methanium/ui/releases/download/0.0.29/methanium-ui.tgz" - mtp: "https://git.methanium.net/methanium/mtp/releases/download/0.3.0-b331b9f6a3/mtp-0.3.0.tgz" + mtp: "https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz" From 8a04b327fcb4f04dfff212af13a5b9e901622818 Mon Sep 17 00:00:00 2001 From: Alois Date: Fri, 28 Aug 2026 20:02:35 +0200 Subject: [PATCH 94/97] chore(mtp): update type-maps --- mtp-type-maps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mtp-type-maps b/mtp-type-maps index a70085b..6e5122f 160000 --- a/mtp-type-maps +++ b/mtp-type-maps @@ -1 +1 @@ -Subproject commit a70085b0c41844745449c9913a361f5bb9bee529 +Subproject commit 6e5122fe44f793c0e0d3229b3d34145ce17c2d31 From 7c9d9529b45ae3574abcfe5dfe33dc0f2e834b0f Mon Sep 17 00:00:00 2001 From: Alois Date: Sat, 29 Aug 2026 12:57:44 +0200 Subject: [PATCH 95/97] feat(workflows): allow manual runs for the dev deploy --- .forgejo/workflows/deploy-dev.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.forgejo/workflows/deploy-dev.yml b/.forgejo/workflows/deploy-dev.yml index c340cbf..7f59ec1 100644 --- a/.forgejo/workflows/deploy-dev.yml +++ b/.forgejo/workflows/deploy-dev.yml @@ -1,4 +1,5 @@ on: + workflow_dispatch: push: branches: - dev From f5461bbd427b8e9be2440784991bc1f2e19b02d5 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Sat, 29 Aug 2026 16:11:24 +0200 Subject: [PATCH 96/97] chore(mtp): update type-maps --- mtp-type-maps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mtp-type-maps b/mtp-type-maps index 6e5122f..f4e45aa 160000 --- a/mtp-type-maps +++ b/mtp-type-maps @@ -1 +1 @@ -Subproject commit 6e5122fe44f793c0e0d3229b3d34145ce17c2d31 +Subproject commit f4e45aa3a3ad0e3c3a257f66857b904a1af7901c From f74ca52f4faf18161a69652c3b149cf5d7143727 Mon Sep 17 00:00:00 2001 From: Alois Date: Sun, 30 Aug 2026 15:58:34 +0200 Subject: [PATCH 97/97] feat(nix-flake): rework nix package --- .forgejo/workflows/deploy-prod.yml | 55 --------- flake.nix | 181 +++++++++++++++++++---------- 2 files changed, 118 insertions(+), 118 deletions(-) diff --git a/.forgejo/workflows/deploy-prod.yml b/.forgejo/workflows/deploy-prod.yml index dd7a5f9..621a0cd 100644 --- a/.forgejo/workflows/deploy-prod.yml +++ b/.forgejo/workflows/deploy-prod.yml @@ -311,58 +311,3 @@ jobs: "$API/repos/$REPO/releases/$release_id" done < "$DELETE_RELEASES" EOF - - - name: Update root flake release hash - env: - TAG: ${{ steps.version.outputs.tag }} - run: | - nix develop .#electron --command bash <<'EOF' - set -eu - - DEB="$(find releases -maxdepth 1 -type f -name 'Tensamin-*-linux-amd64.deb' -print -quit)" - test -n "$DEB" - - HASH="$(node -e 'const fs = require("fs"); const crypto = require("crypto"); const file = process.argv[1]; console.log("sha256-" + crypto.createHash("sha256").update(fs.readFileSync(file)).digest("base64"));' "$DEB")" - export HASH - - node -e ' - const fs = require("fs"); - const version = process.env.TAG; - const hash = process.env.HASH; - let content = fs.readFileSync("flake.nix", "utf8"); - content = content.replace(/version = "[^"]+";/, `version = "${version}";`); - content = content.replace(/x86_64DebHash = "sha256-[^"]+";/, `x86_64DebHash = "${hash}";`); - fs.writeFileSync("flake.nix", content); - ' - - if git diff --quiet -- flake.nix; then - echo "flake.nix already has the current release hash on main." - else - git add flake.nix - git -c user.name="forgejo-actions" -c user.email="forgejo-actions@localhost" commit -m "(qol): update release flake hash" - git push - fi - - git fetch origin dev - git worktree add ../dev-flake-update origin/dev - cd ../dev-flake-update - - node -e ' - const fs = require("fs"); - const version = process.env.TAG; - const hash = process.env.HASH; - let content = fs.readFileSync("flake.nix", "utf8"); - content = content.replace(/version = "[^"]+";/, `version = "${version}";`); - content = content.replace(/x86_64DebHash = "sha256-[^"]+";/, `x86_64DebHash = "${hash}";`); - fs.writeFileSync("flake.nix", content); - ' - - if git diff --quiet -- flake.nix; then - echo "flake.nix already has the current release hash on dev." - exit 0 - fi - - git add flake.nix - git -c user.name="forgejo-actions" -c user.email="forgejo-actions@localhost" commit -m "(qol): update release flake hash" - git push origin HEAD:dev - EOF diff --git a/flake.nix b/flake.nix index e02a001..0b0d63c 100644 --- a/flake.nix +++ b/flake.nix @@ -17,8 +17,6 @@ systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; version = "0.0.11"; - x86_64DebHash = "sha256-iMEgdjY8Ghlx6K/YzKC5JAZbeHNJDIFHm8MKmM4efaI="; - forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}"; in { packages = forAllSystems ( @@ -32,8 +30,6 @@ android_sdk.accept_license = true; }; }; - debArtifact = "Tensamin-${version}-linux-amd64.deb"; - electronRuntimeLibs = with pkgs; [ alsa-lib at-spi2-atk @@ -75,71 +71,130 @@ libXtst libxcb ]; - packageDeb = - src: - pkgs.stdenv.mkDerivation { - pname = "tensamin"; - inherit version src; - - nativeBuildInputs = with pkgs; [ - autoPatchelfHook - dpkg - makeWrapper - ]; - buildInputs = electronRuntimeLibs; - - dontConfigure = true; - dontBuild = true; - - unpackPhase = '' - runHook preUnpack - dpkg-deb -x "$src" . - runHook postUnpack - ''; - - installPhase = '' - runHook preInstall - - mkdir -p "$out" - cp -r opt "$out/" - cp -r usr/* "$out/" - - mkdir -p "$out/bin" - makeWrapper "$out/opt/Tensamin/tensamin" "$out/bin/tensamin" \ - --prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath electronRuntimeLibs}" - - substituteInPlace "$out/share/applications/Tensamin.desktop" \ - --replace-fail "Exec=/opt/Tensamin/tensamin" "Exec=tensamin" - - runHook postInstall - ''; + electron = pkgs.electron; + pnpm = pkgs.pnpm; + mtpTypeMaps = pkgs.fetchgit { + url = "https://git.methanium.net/tensamin/mtp-type-maps"; + rev = "6e5122fe44f793c0e0d3229b3d34145ce17c2d31"; + hash = "sha256-/4n8F0YLJaLncefKL907P5l+en1CTjpgdFmLBF3gbiQ="; + }; + mtpSource = pkgs.fetchzip { + url = "https://git.methanium.net/methanium/mtp/releases/download/0.3.0-dev-c7c7afe/mtp-0.3.0.tgz"; + hash = "sha256-XLTa8DxP93Q4hBHRCLUzCPOqkbdb4V3aZxE5Iuq+kW0="; + }; + mtpCargoDeps = pkgs.rustPlatform.fetchCargoVendor { + src = mtpSource; + hash = "sha256-8MZ65N/EtWPAggal0JkGDx3WSn+LxWQORinkqVbsrys="; + }; + wasmBindgenCliSource = pkgs.fetchCrate { + pname = "wasm-bindgen-cli"; + version = "0.2.127"; + hash = "sha256-di+qBAdd7pENLiIB9CoZoab+W5xeDoByMREcCGTSzWo="; + }; + wasmBindgenCli = pkgs.buildWasmBindgenCli { + src = wasmBindgenCliSource; + cargoDeps = pkgs.rustPlatform.fetchCargoVendor { + src = wasmBindgenCliSource; + hash = "sha256-FTv2GZIAQs0ePdIZXIXil7JbZ6kIT05VG6vqC1qNFxQ="; }; - defaultPackage = packageDeb ( - pkgs.fetchurl { - url = "${forgejoBaseUrl}/${debArtifact}"; - hash = x86_64DebHash; - } - ); - localDebPath = builtins.getEnv "TENSAMIN_DEB"; - localPathPackage = - if localDebPath == "" then - pkgs.writeShellScriptBin "tensamin" '' - echo "Set TENSAMIN_DEB to a local .deb path and run with --impure." >&2 - exit 1 - '' - else - packageDeb ( - builtins.path { - path = localDebPath; - name = debArtifact; - } - ); + }; + desktopItem = pkgs.makeDesktopItem { + name = "tensamin"; + desktopName = "Tensamin"; + exec = "tensamin"; + icon = "tensamin"; + startupWMClass = "Tensamin"; + categories = [ "Network" ]; + }; + defaultPackage = pkgs.stdenv.mkDerivation (finalAttrs: { + pname = "tensamin"; + inherit version; + src = self; + + pnpmDeps = pkgs.fetchPnpmDeps { + inherit (finalAttrs) pname version src; + inherit pnpm; + fetcherVersion = 4; + hash = "sha256-imP3MTr1YLc28Z9n617m0Wt/6vPirFznzoriKzojlEg="; + }; + + nativeBuildInputs = with pkgs; [ + copyDesktopItems + makeWrapper + nodejs_22 + pnpm + pnpmConfigHook + cargo + lld + rustc + wasm-pack + wasmBindgenCli + binaryen + ]; + + env.ELECTRON_SKIP_BINARY_DOWNLOAD = 1; + + postPatch = '' + rm -rf mtp-type-maps + ln -s ${mtpTypeMaps} mtp-type-maps + + node -e ' + const fs = require("fs"); + const path = "apps/electron/package.json"; + const pkg = JSON.parse(fs.readFileSync(path, "utf8")); + pkg.version = "${version}"; + fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + "\n"); + ' + ''; + + buildPhase = '' + runHook preBuild + + mkdir -p "$HOME/.cargo" + substitute ${mtpCargoDeps}/.cargo/config.toml "$HOME/.cargo/config.toml" \ + --replace-fail @vendor@ ${mtpCargoDeps} + + pnpm run copy-licenses + pnpm run build:packages + pnpm run build:web + pnpm --dir apps/tauri run gen-icons + pnpm --dir apps/electron run build + pnpm --dir apps/electron exec electron-builder --dir --linux --publish never \ + --config.electronDist=${electron.dist} \ + --config.electronVersion=${electron.version} + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p "$out/lib/tensamin" "$out/bin" + cp -r apps/electron/release/linux-unpacked/. "$out/lib/tensamin/" + + makeWrapper "$out/lib/tensamin/tensamin" "$out/bin/tensamin" \ + --prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath electronRuntimeLibs}" + + install -Dm644 apps/electron/build/icons/icon.png \ + "$out/share/icons/hicolor/512x512/apps/tensamin.png" + + runHook postInstall + ''; + + desktopItems = [ desktopItem ]; + + meta = { + description = "Tensamin desktop client"; + homepage = "https://git.methanium.net/tensamin/client"; + mainProgram = "tensamin"; + platforms = pkgs.lib.platforms.linux; + }; + }); in { default = defaultPackage; tensamin = defaultPackage; electron = defaultPackage; - localPathForDev = localPathPackage; } );