diff --git a/.github/update.log b/.github/update.log index 2d60b58002..fc938309b8 100644 --- a/.github/update.log +++ b/.github/update.log @@ -1112,3 +1112,4 @@ Update On Tue Sep 2 20:34:24 CEST 2025 Update On Wed Sep 3 20:39:00 CEST 2025 Update On Thu Sep 4 20:39:26 CEST 2025 Update On Fri Sep 5 20:37:42 CEST 2025 +Update On Sat Sep 6 20:35:46 CEST 2025 diff --git a/bbdown/BBDown/BBDownDownloadUtil.cs b/bbdown/BBDown/BBDownDownloadUtil.cs index 61b6736d68..893e56f3d4 100644 --- a/bbdown/BBDown/BBDownDownloadUtil.cs +++ b/bbdown/BBDown/BBDownDownloadUtil.cs @@ -26,8 +26,14 @@ internal static class BBDownDownloadUtil private static async Task RangeDownloadToTmpAsync(int id, string url, string tmpName, long fromPosition, long? toPosition, Action onProgress, bool failOnRangeNotSupported = false) { DateTimeOffset? lastTime = File.Exists(tmpName) ? new FileInfo(tmpName).LastWriteTimeUtc : null; - using var fileStream = new FileStream(tmpName, FileMode.Create); + using var fileStream = new FileStream(tmpName, FileMode.OpenOrCreate); fileStream.Seek(0, SeekOrigin.End); + if (toPosition > 0 && fileStream.Position == toPosition - fromPosition + 1) + { + // 已下载完成 直接汇报进度并跳过下载 + onProgress(id, fileStream.Position, fileStream.Position); + return; + } var downloadedBytes = fromPosition + fileStream.Position; using var httpRequestMessage = new HttpRequestMessage(); diff --git a/bbdown/BBDown/Program.Methods.cs b/bbdown/BBDown/Program.Methods.cs index 96b97fb3ca..ab4357498b 100644 --- a/bbdown/BBDown/Program.Methods.cs +++ b/bbdown/BBDown/Program.Methods.cs @@ -503,8 +503,6 @@ internal partial class Program { if (downloadConfig.MultiThread && !url.Contains("-cmcc-")) { - // 下载前先清理残片 - foreach (var file in new DirectoryInfo(Path.GetDirectoryName(destPath)!).EnumerateFiles("*.?clip")) file.Delete(); await MultiThreadDownloadFileAsync(url, destPath, downloadConfig); Log($"合并{(video ? "视频" : "音频")}分片..."); CombineMultipleFilesIntoSingleFile(GetFiles(Path.GetDirectoryName(destPath)!, $".{(video ? "v" : "a")}clip"), destPath); diff --git a/bbdown/BBDown/ProgressBar.cs b/bbdown/BBDown/ProgressBar.cs index 48245a7928..283803a9c3 100644 --- a/bbdown/BBDown/ProgressBar.cs +++ b/bbdown/BBDown/ProgressBar.cs @@ -93,10 +93,9 @@ class ProgressBar : IDisposable, IProgress if (disposed) return; int progressBlockCount = (int)(currentProgress * blockCount); - int percent = (int)(currentProgress * 100); - string text = string.Format(" [{0}{1}] {2,3}% {3}{4}", - new string('#', progressBlockCount), new string('-', blockCount - progressBlockCount), - percent, + double percent = currentProgress * 100; + string text = string.Format(" [{0}{1}] {2,3:0.00}% {3}{4}", + new string('#', progressBlockCount), new string('-', blockCount - progressBlockCount), percent, animation[animationIndex++ % animation.Length], speedString); UpdateText(text); diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json index ca3e87586a..ff36887196 100644 --- a/clash-nyanpasu/frontend/nyanpasu/package.json +++ b/clash-nyanpasu/frontend/nyanpasu/package.json @@ -22,7 +22,7 @@ "@mui/x-date-pickers": "8.11.1", "@nyanpasu/interface": "workspace:^", "@nyanpasu/ui": "workspace:^", - "@tailwindcss/postcss": "4.1.12", + "@tailwindcss/postcss": "4.1.13", "@tanstack/router-zod-adapter": "1.81.5", "@tauri-apps/api": "2.8.0", "@types/json-schema": "7.0.15", @@ -83,7 +83,7 @@ "meta-json-schema": "1.19.13", "monaco-yaml": "5.4.0", "nanoid": "5.1.5", - "sass-embedded": "1.92.0", + "sass-embedded": "1.92.1", "shiki": "2.5.0", "unplugin-auto-import": "20.1.0", "unplugin-icons": "22.2.0", diff --git a/clash-nyanpasu/frontend/ui/package.json b/clash-nyanpasu/frontend/ui/package.json index ec59cb6ea6..a24a469911 100644 --- a/clash-nyanpasu/frontend/ui/package.json +++ b/clash-nyanpasu/frontend/ui/package.json @@ -29,7 +29,7 @@ "react-error-boundary": "6.0.0", "react-i18next": "15.7.3", "react-use": "17.6.0", - "tailwindcss": "4.1.12", + "tailwindcss": "4.1.13", "vite": "7.1.4", "vite-tsconfig-paths": "5.1.4" }, @@ -38,7 +38,7 @@ "@types/d3-interpolate-path": "2.0.3", "clsx": "2.1.1", "d3-interpolate-path": "2.3.0", - "sass-embedded": "1.92.0", + "sass-embedded": "1.92.1", "tailwind-merge": "3.3.1", "typescript-plugin-css-modules": "5.2.0", "vite-plugin-dts": "4.5.4" diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index 65632fec64..3a5008966c 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,7 +2,7 @@ "manifest_version": 1, "latest": { "mihomo": "v1.19.13", - "mihomo_alpha": "alpha-f8ee5c1", + "mihomo_alpha": "alpha-fed4b36", "clash_rs": "v0.9.0", "clash_premium": "2023-09-05-gdcc8d87", "clash_rs_alpha": "0.9.0-alpha+sha.37539fb" @@ -69,5 +69,5 @@ "linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf" } }, - "updated_at": "2025-09-04T22:20:59.412Z" + "updated_at": "2025-09-05T22:20:49.036Z" } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index 1e41553e81..b395076d3f 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -66,14 +66,14 @@ "@tauri-apps/cli": "2.8.4", "@types/fs-extra": "11.0.4", "@types/lodash-es": "4.17.12", - "@types/node": "24.3.0", + "@types/node": "24.3.1", "@typescript-eslint/eslint-plugin": "8.42.0", "@typescript-eslint/parser": "8.42.0", "autoprefixer": "10.4.21", "conventional-changelog-conventionalcommits": "9.1.0", "cross-env": "10.0.0", - "dedent": "1.6.0", - "eslint": "9.34.0", + "dedent": "1.7.0", + "eslint": "9.35.0", "eslint-config-prettier": "10.1.8", "eslint-import-resolver-alias": "1.1.2", "eslint-plugin-html": "8.1.3", @@ -100,12 +100,12 @@ "react-devtools": "6.1.5", "stylelint": "16.23.1", "stylelint-config-html": "1.1.0", - "stylelint-config-recess-order": "7.2.0", + "stylelint-config-recess-order": "7.3.0", "stylelint-config-standard": "39.0.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-order": "7.0.0", "stylelint-scss": "6.12.1", - "tailwindcss": "4.1.12", + "tailwindcss": "4.1.13", "tsx": "4.20.5", "typescript": "5.9.2", "typescript-eslint": "8.42.0" diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index acb2c48adb..3765731c4e 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -24,13 +24,13 @@ importers: devDependencies: '@commitlint/cli': specifier: 19.8.1 - version: 19.8.1(@types/node@24.3.0)(typescript@5.9.2) + version: 19.8.1(@types/node@24.3.1)(typescript@5.9.2) '@commitlint/config-conventional': specifier: 19.8.1 version: 19.8.1 '@eslint/compat': specifier: 1.3.2 - version: 1.3.2(eslint@9.34.0(jiti@2.5.1)) + version: 1.3.2(eslint@9.35.0(jiti@2.5.1)) '@eslint/eslintrc': specifier: 3.3.1 version: 3.3.1 @@ -47,14 +47,14 @@ importers: specifier: 4.17.12 version: 4.17.12 '@types/node': - specifier: 24.3.0 - version: 24.3.0 + specifier: 24.3.1 + version: 24.3.1 '@typescript-eslint/eslint-plugin': specifier: 8.42.0 - version: 8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + version: 8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) '@typescript-eslint/parser': specifier: 8.42.0 - version: 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + version: 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) autoprefixer: specifier: 10.4.21 version: 10.4.21(postcss@8.5.6) @@ -65,53 +65,53 @@ importers: specifier: 10.0.0 version: 10.0.0 dedent: - specifier: 1.6.0 - version: 1.6.0(babel-plugin-macros@3.1.0) + specifier: 1.7.0 + version: 1.7.0(babel-plugin-macros@3.1.0) eslint: - specifier: 9.34.0 - version: 9.34.0(jiti@2.5.1) + specifier: 9.35.0 + version: 9.35.0(jiti@2.5.1) eslint-config-prettier: specifier: 10.1.8 - version: 10.1.8(eslint@9.34.0(jiti@2.5.1)) + version: 10.1.8(eslint@9.35.0(jiti@2.5.1)) eslint-import-resolver-alias: specifier: 1.1.2 - version: 1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1))) + version: 1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))) eslint-plugin-html: specifier: 8.1.3 version: 8.1.3 eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)) + version: 2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)) eslint-plugin-n: specifier: 17.21.3 - version: 17.21.3(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + version: 17.21.3(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) eslint-plugin-prettier: specifier: 5.5.4 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1))(prettier@3.6.2) + version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(prettier@3.6.2) eslint-plugin-promise: specifier: 7.2.1 - version: 7.2.1(eslint@9.34.0(jiti@2.5.1)) + version: 7.2.1(eslint@9.35.0(jiti@2.5.1)) eslint-plugin-react: specifier: 7.37.5 - version: 7.37.5(eslint@9.34.0(jiti@2.5.1)) + version: 7.37.5(eslint@9.35.0(jiti@2.5.1)) eslint-plugin-react-compiler: specifier: 19.1.0-rc.2 - version: 19.1.0-rc.2(eslint@9.34.0(jiti@2.5.1)) + version: 19.1.0-rc.2(eslint@9.35.0(jiti@2.5.1)) eslint-plugin-react-hooks: specifier: 5.2.0 - version: 5.2.0(eslint@9.34.0(jiti@2.5.1)) + version: 5.2.0(eslint@9.35.0(jiti@2.5.1)) globals: specifier: 16.3.0 version: 16.3.0 knip: specifier: 5.63.1 - version: 5.63.1(@types/node@24.3.0)(typescript@5.9.2) + version: 5.63.1(@types/node@24.3.1)(typescript@5.9.2) lint-staged: specifier: 16.1.6 version: 16.1.6 neostandard: specifier: 0.12.2 - version: 0.12.2(@typescript-eslint/utils@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + version: 0.12.2(@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) npm-run-all2: specifier: 8.0.4 version: 8.0.4 @@ -149,8 +149,8 @@ importers: specifier: 1.1.0 version: 1.1.0(postcss-html@1.8.0)(stylelint@16.23.1(typescript@5.9.2)) stylelint-config-recess-order: - specifier: 7.2.0 - version: 7.2.0(stylelint-order@7.0.0(stylelint@16.23.1(typescript@5.9.2)))(stylelint@16.23.1(typescript@5.9.2)) + specifier: 7.3.0 + version: 7.3.0(stylelint-order@7.0.0(stylelint@16.23.1(typescript@5.9.2)))(stylelint@16.23.1(typescript@5.9.2)) stylelint-config-standard: specifier: 39.0.0 version: 39.0.0(stylelint@16.23.1(typescript@5.9.2)) @@ -164,8 +164,8 @@ importers: specifier: 6.12.1 version: 6.12.1(stylelint@16.23.1(typescript@5.9.2)) tailwindcss: - specifier: 4.1.12 - version: 4.1.12 + specifier: 4.1.13 + version: 4.1.13 tsx: specifier: 4.20.5 version: 4.20.5 @@ -174,7 +174,7 @@ importers: version: 5.9.2 typescript-eslint: specifier: 8.42.0 - version: 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + version: 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) frontend/interface: dependencies: @@ -249,8 +249,8 @@ importers: specifier: workspace:^ version: link:../ui '@tailwindcss/postcss': - specifier: 4.1.12 - version: 4.1.12 + specifier: 4.1.13 + version: 4.1.13 '@tanstack/router-zod-adapter': specifier: 1.81.5 version: 1.81.5(@tanstack/react-router@1.131.35(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.1.5) @@ -362,7 +362,7 @@ importers: version: 1.131.35(@tanstack/react-router@1.131.35(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.35)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.5)(tiny-invariant@1.3.3) '@tanstack/router-plugin': specifier: 1.131.35 - version: 1.131.35(@tanstack/react-router@1.131.35(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) + version: 1.131.35(@tanstack/react-router@1.131.35(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) '@tauri-apps/plugin-clipboard-manager': specifier: 2.3.0 version: 2.3.0 @@ -398,13 +398,13 @@ importers: version: 13.15.3 '@vitejs/plugin-legacy': specifier: 7.2.1 - version: 7.2.1(terser@5.36.0)(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) + version: 7.2.1(terser@5.36.0)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) '@vitejs/plugin-react': specifier: 5.0.2 - version: 5.0.2(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.0.2(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) '@vitejs/plugin-react-swc': specifier: 4.0.1 - version: 4.0.1(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) + version: 4.0.1(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) change-case: specifier: 5.4.4 version: 5.4.4 @@ -427,8 +427,8 @@ importers: specifier: 5.1.5 version: 5.1.5 sass-embedded: - specifier: 1.92.0 - version: 1.92.0 + specifier: 1.92.1 + version: 1.92.1 shiki: specifier: 2.5.0 version: 2.5.0 @@ -443,19 +443,19 @@ importers: version: 13.15.15 vite: specifier: 7.1.4 - version: 7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) + version: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) vite-plugin-html: specifier: 3.2.2 - version: 3.2.2(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) + version: 3.2.2(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) vite-plugin-sass-dts: specifier: 1.3.31 - version: 1.3.31(postcss@8.5.6)(prettier@3.6.2)(sass-embedded@1.92.0)(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) + version: 1.3.31(postcss@8.5.6)(prettier@3.6.2)(sass-embedded@1.92.1)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) vite-plugin-svgr: specifier: 4.5.0 - version: 4.5.0(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) + version: 4.5.0(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) vite-tsconfig-paths: specifier: 5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) zod: specifier: 4.1.5 version: 4.1.5 @@ -491,7 +491,7 @@ importers: version: 19.1.12 '@vitejs/plugin-react': specifier: 5.0.2 - version: 5.0.2(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.0.2(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) ahooks: specifier: 3.9.5 version: 3.9.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -517,14 +517,14 @@ importers: specifier: 17.6.0 version: 17.6.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) tailwindcss: - specifier: 4.1.12 - version: 4.1.12 + specifier: 4.1.13 + version: 4.1.13 vite: specifier: 7.1.4 - version: 7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) + version: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) vite-tsconfig-paths: specifier: 5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) devDependencies: '@emotion/react': specifier: 11.14.0 @@ -539,8 +539,8 @@ importers: specifier: 2.3.0 version: 2.3.0 sass-embedded: - specifier: 1.92.0 - version: 1.92.0 + specifier: 1.92.1 + version: 1.92.1 tailwind-merge: specifier: 3.3.1 version: 3.3.1 @@ -549,7 +549,7 @@ importers: version: 5.2.0(typescript@5.9.2) vite-plugin-dts: specifier: 4.5.4 - version: 4.5.4(@types/node@24.3.0)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) + version: 4.5.4(@types/node@24.3.1)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)) scripts: dependencies: @@ -560,8 +560,8 @@ importers: specifier: 1.7.0 version: 1.7.0 '@types/semver': - specifier: 7.7.0 - version: 7.7.0 + specifier: 7.7.1 + version: 7.7.1 figlet: specifier: 1.8.2 version: 1.8.2 @@ -1708,6 +1708,12 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.8.0': + resolution: {integrity: sha512-MJQFqrZgcW0UNYLGOuQpey/oTN59vyWwplvCGZztn1cKz9agZPPYpJB7h2OMmuu7VLqkvEjN8feFZJmxNF9D+Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/regexpp@4.12.1': resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -1737,8 +1743,8 @@ packages: resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.34.0': - resolution: {integrity: sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw==} + '@eslint/js@9.35.0': + resolution: {integrity: sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.6': @@ -2930,65 +2936,65 @@ packages: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} - '@tailwindcss/node@4.1.12': - resolution: {integrity: sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==} + '@tailwindcss/node@4.1.13': + resolution: {integrity: sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==} - '@tailwindcss/oxide-android-arm64@4.1.12': - resolution: {integrity: sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ==} + '@tailwindcss/oxide-android-arm64@4.1.13': + resolution: {integrity: sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.12': - resolution: {integrity: sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw==} + '@tailwindcss/oxide-darwin-arm64@4.1.13': + resolution: {integrity: sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.12': - resolution: {integrity: sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==} + '@tailwindcss/oxide-darwin-x64@4.1.13': + resolution: {integrity: sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.12': - resolution: {integrity: sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww==} + '@tailwindcss/oxide-freebsd-x64@4.1.13': + resolution: {integrity: sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12': - resolution: {integrity: sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': + resolution: {integrity: sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.12': - resolution: {integrity: sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g==} + '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': + resolution: {integrity: sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.1.12': - resolution: {integrity: sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==} + '@tailwindcss/oxide-linux-arm64-musl@4.1.13': + resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.1.12': - resolution: {integrity: sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==} + '@tailwindcss/oxide-linux-x64-gnu@4.1.13': + resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.1.12': - resolution: {integrity: sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==} + '@tailwindcss/oxide-linux-x64-musl@4.1.13': + resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-wasm32-wasi@4.1.12': - resolution: {integrity: sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==} + '@tailwindcss/oxide-wasm32-wasi@4.1.13': + resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -2999,24 +3005,24 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.12': - resolution: {integrity: sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg==} + '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': + resolution: {integrity: sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.12': - resolution: {integrity: sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA==} + '@tailwindcss/oxide-win32-x64-msvc@4.1.13': + resolution: {integrity: sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.12': - resolution: {integrity: sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==} + '@tailwindcss/oxide@4.1.13': + resolution: {integrity: sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==} engines: {node: '>= 10'} - '@tailwindcss/postcss@4.1.12': - resolution: {integrity: sha512-5PpLYhCAwf9SJEeIsSmCDLgyVfdBhdBpzX1OJ87anT9IVR0Z9pjM0FNixCAUAHGnMBGB8K99SwAheXrT0Kh6QQ==} + '@tailwindcss/postcss@4.1.13': + resolution: {integrity: sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==} '@tanstack/history@1.131.2': resolution: {integrity: sha512-cs1WKawpXIe+vSTeiZUuSBy8JFjEuDgdMKZFRLKwQysKo8y2q6Q1HvS74Yw+m5IhOW1nTZooa6rlgdfXcgFAaw==} @@ -3433,8 +3439,8 @@ packages: '@types/node@16.18.108': resolution: {integrity: sha512-fj42LD82fSv6yN9C6Q4dzS+hujHj+pTv0IpRR3kI20fnYeS0ytBpjFO9OjmDowSPPt4lNKN46JLaKbCyP+BW2A==} - '@types/node@24.3.0': - resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==} + '@types/node@24.3.1': + resolution: {integrity: sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -3464,8 +3470,8 @@ packages: '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} - '@types/semver@7.7.0': - resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==} + '@types/semver@7.7.1': + resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} '@types/unist@2.0.10': resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} @@ -4611,8 +4617,8 @@ packages: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} - dedent@1.6.0: - resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==} + dedent@1.7.0: + resolution: {integrity: sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==} peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: @@ -5063,8 +5069,8 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.34.0: - resolution: {integrity: sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg==} + eslint@9.35.0: + resolution: {integrity: sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -7479,112 +7485,112 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass-embedded-all-unknown@1.92.0: - resolution: {integrity: sha512-0VcRBilndf8Iot7zfKKEYH7Ig4JBRjltf7Ba9dNL6wtv0m1a36cm8FgZFofrXtDjUgVTV/aEH/Xw4zBUs6vFYA==} + sass-embedded-all-unknown@1.92.1: + resolution: {integrity: sha512-5t6/YZf+vhO3OY/49h8RCL6Cwo78luva0M+TnTM9gu9ASffRXAuOVLNKciSXa3loptyemDDS6IU5/dVH5w0KmA==} cpu: ['!arm', '!arm64', '!riscv64', '!x64'] - sass-embedded-android-arm64@1.92.0: - resolution: {integrity: sha512-m0JY0QyskN77AFpA8FKxqXZNWSzrPvKOvZqOu1DwEEipyHuSdiAVFDHZ6EpI3aABxCXE3jgkP+Ij2mb4hiLxFw==} + sass-embedded-android-arm64@1.92.1: + resolution: {integrity: sha512-Q+UruGb7yKawHagVmVDRRKsnc4mJZvWMBnuRCu2coJo2FofyqBmXohVGXbxko97sYceA9TJTrUEx3WVKQUNCbQ==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [android] - sass-embedded-android-arm@1.92.0: - resolution: {integrity: sha512-0NH0zElKL5gLdNcWFzYX/bqtpoFq5ogcU+4vLdmpBXA9Zl5NFPXAPRA6K8pgjQNWpnV7bG05JSIVPuNKZ60Ptg==} + sass-embedded-android-arm@1.92.1: + resolution: {integrity: sha512-4EjpVVzuksERdgAd4BqeSXFnWtWN3DSRyEIUPJ7BhcS9sfDh2Gf6miI2kNTvIQLJ2XIJynDDcEQ8a1U9KwKUTQ==} engines: {node: '>=14.0.0'} cpu: [arm] os: [android] - sass-embedded-android-riscv64@1.92.0: - resolution: {integrity: sha512-wfVRf2PFR15vCgJE3SWLZQRo+98xm7vKvpHiaPU4satutwMKC8yXxDvsc7hFBqQYBtqHNK5ap5dZSXlgdGGZrA==} + sass-embedded-android-riscv64@1.92.1: + resolution: {integrity: sha512-nCY5btLlX7W7Jc6cCL6D2Yklpiu540EJ2G08YVGu12DrAMCBzqM347CSRf2ojp1H8jyhvmLkaFwnrJWzh+6S+w==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [android] - sass-embedded-android-x64@1.92.0: - resolution: {integrity: sha512-bc1c3OMdfrYoiIzVzsMI3KBnIa4mEumg7jHzonkDUIUWrfUNsbzlO+UXX1CcRyfaOIqyKNNZLVvBCz8EwmUsbQ==} + sass-embedded-android-x64@1.92.1: + resolution: {integrity: sha512-qYWR3bftJ77aLYwYDFuzDI4dcwVVixxqQxlIQWNGkHRCexj614qGSSHemr18C2eVj3mjXAQxTQxU68U7pkGPAA==} engines: {node: '>=14.0.0'} cpu: [x64] os: [android] - sass-embedded-darwin-arm64@1.92.0: - resolution: {integrity: sha512-vZh1WCL2QlQyTlAD8snmC8W90XBZI/125o15bfKkGbUzV58dkZJf413hk6JVQS2+a0lZT4GxvrlGH1fSaSNTug==} + sass-embedded-darwin-arm64@1.92.1: + resolution: {integrity: sha512-g2yQ3txjMYLKMjL2cW1xRO9nnV3ijf95NbX/QShtV6tiVUETZNWDsRMDEwBNGYY6PTE/UZerjJL1R/2xpQg6WA==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [darwin] - sass-embedded-darwin-x64@1.92.0: - resolution: {integrity: sha512-4vJsXpOQAgU+KrrW/3POvhnfkG9iJ4gU8ujeEDXqCSSY2M+5B/j0S6iXB7nu3Z9MfmCl8V4B6xyeB0EWE5Ul0g==} + sass-embedded-darwin-x64@1.92.1: + resolution: {integrity: sha512-eH+fgxLQhTEPjZPCgPAVuX5e514Qp/4DMAUMtlNShv4cr4TD5qOp1XlsPYR/b7uE7p2cKFkUpUn/bHNqJ2ay4A==} engines: {node: '>=14.0.0'} cpu: [x64] os: [darwin] - sass-embedded-linux-arm64@1.92.0: - resolution: {integrity: sha512-HH4LNY1svM2Lv6NCxqOQca42hzG/o55ON9X3T0R18Rl9kVb3y5qiJpdrHh7sSlZWF4qhHYbRc9BIc+Tw142oog==} + sass-embedded-linux-arm64@1.92.1: + resolution: {integrity: sha512-dNmlpGeZkry1BofhAdGFBXrpM69y9LlYuNnncf+HfsOOUtj8j0q1RwS+zb5asknhKFUOAG8GCGRY1df7Rwu35g==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] - sass-embedded-linux-arm@1.92.0: - resolution: {integrity: sha512-HMjTDjIT8bHwAVd0c8r8QvGxGZwJg3H06/Y5ZiaiwVGiZtYS9jfef6LnrPw8LY5cOG8wm9RZ9AgVqvkL7E2jBQ==} + sass-embedded-linux-arm@1.92.1: + resolution: {integrity: sha512-cT3w8yoQTqrtZvWLJeutEGmawITDTY4J6oSVQjeDcPnnoPt0gOFxem8YMznraACXvahw/2+KJDH33BTNgiPo0A==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] - sass-embedded-linux-musl-arm64@1.92.0: - resolution: {integrity: sha512-xYzZDmcPb3BsaD6qlRTqZqtyMOZfGCSKJBZYj2ZRJiKDDr1sqPSIqKx6G8jc1wJAVdvoNp5tzENnCfY7NRkxNA==} + sass-embedded-linux-musl-arm64@1.92.1: + resolution: {integrity: sha512-TfiEBkCyNzVoOhjHXUT+vZ6+p0ueDbvRw6f4jHdkvljZzXdXMby4wh7BU1odl69rgRTkSvYKhgbErRLDR/F7pQ==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] - sass-embedded-linux-musl-arm@1.92.0: - resolution: {integrity: sha512-qJDCXm379yRT9+8wKSi6nHFCOODTmD6XmE8rqmMozKo6kvCM+Y3sAMlHrT/0+pfzlGh1JSamkoYIo/ODn+LRVA==} + sass-embedded-linux-musl-arm@1.92.1: + resolution: {integrity: sha512-nPBos6lI31ef2zQhqTZhFOU7ar4impJbLIax0XsqS269YsiCwjhk11VmUloJTpFlJuKMiVXNo7dPx+katxhD/Q==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] - sass-embedded-linux-musl-riscv64@1.92.0: - resolution: {integrity: sha512-ZD3a6c7YvAjp1lEkKyaQpHc5EuetQ0RU3YoTfjwHiyWwezsuJHZc4hkS7SXWbZNEvi7tc2U1bdt4nSdx9c5Qxw==} + sass-embedded-linux-musl-riscv64@1.92.1: + resolution: {integrity: sha512-R+RcJA4EYpJDE9JM1GgPYgZo7x94FlxZ6jPodOQkEaZ1S9kvXVCuP5X/0PXRPhu08KJOfeMsAElzfdAjUf7KJg==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] - sass-embedded-linux-musl-x64@1.92.0: - resolution: {integrity: sha512-ShivGoEKmpyL57hQB9K+EMEOWOo+LuwH5eIM2T0sRIHW5n28IS6h12R3WEJVf+PYtSi9FKWazy7kzeLefya6fQ==} + sass-embedded-linux-musl-x64@1.92.1: + resolution: {integrity: sha512-/HolYRGXJjx8nLw6oj5ZrkR7PFM7X/5kE4MYZaFMpDIPIcw3bqB2fUXLo/MYlRLsw7gBAT6hJAMBrNdKuTphfw==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] - sass-embedded-linux-riscv64@1.92.0: - resolution: {integrity: sha512-CTZF8rMYBS4JsGGFMUwdPExq6DxhONXQv9omKpVmuleRw52Isx37GaMTQg5zSxunS6QfwqCyUysjWXTLe8khHA==} + sass-embedded-linux-riscv64@1.92.1: + resolution: {integrity: sha512-b9bxe0CMsbSsLx3nrR0cq8xpIkoAC6X36o4DGMITF3m2v3KsojC7ru9X0Gz+zUFr6rwpq/0lTNzFLNu6sPNo3w==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] - sass-embedded-linux-x64@1.92.0: - resolution: {integrity: sha512-jAY4tzhSUUDUYSl0m+GQub/ZpVk00Pn4ybHeUICAYSQj043A9rkag+LSKDGCvC/0MptMM+/HkIDAC06tRY4PeQ==} + sass-embedded-linux-x64@1.92.1: + resolution: {integrity: sha512-xuiK5Jp5NldW4bvlC7AuX1Wf7o0gLZ3md/hNg+bkTvxtCDgnUHtfdo8Q+xWP11bD9QX31xXFWpmUB8UDLi6XQQ==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] - sass-embedded-unknown-all@1.92.0: - resolution: {integrity: sha512-s0UF1jquqhrxg0dl/0E+L5tCH1zv1ueF+m3VgJukDkDSTW+nb7wpCGcm8csGoSXnP8+dq53jtUXVtt8sPLr8ZQ==} + sass-embedded-unknown-all@1.92.1: + resolution: {integrity: sha512-AT9oXvtNY4N+Nd0wvoWqq9A5HjdH/X3aUH4boQUtXyaJ/9DUwnQmBpP5Gtn028ZS8exOGBdobmmWAuigv0k/OA==} os: ['!android', '!darwin', '!linux', '!win32'] - sass-embedded-win32-arm64@1.92.0: - resolution: {integrity: sha512-K8x+q2W0VyGPBtO3b0AlpecGOk47ce2FkEX0WD1gEexpbRCytQ+udDACHQGXpwWYPgSIT9ky0IASzDVT1fjMcw==} + sass-embedded-win32-arm64@1.92.1: + resolution: {integrity: sha512-KvmpQjY9yTBMtTYz4WBqetlv9bGaDW1aStcu7MSTbH7YiSybX/9fnxlCAEQv1WlIidQhcJAiyk0Eae+LGK7cIQ==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [win32] - sass-embedded-win32-x64@1.92.0: - resolution: {integrity: sha512-b0051n7EwSvH580u8LjsCAj2US1F59FY6/GbWJWlE2bidzY86/f8ovl4LsGY/uM3lNzWQlA/0BGmdAm44d/qJg==} + sass-embedded-win32-x64@1.92.1: + resolution: {integrity: sha512-B6Nz/GbH7Vkpb2TkQHsGcczWM5t+70VWopWF1x5V5yxLpA8ZzVQ7NTKKi+jDoVY2Efu6ZyzgT9n5KgG2kWliXA==} engines: {node: '>=14.0.0'} cpu: [x64] os: [win32] - sass-embedded@1.92.0: - resolution: {integrity: sha512-daqnoAA+AmXvcL1fvJRMd4RDPZM2s27qYxb51c5TYc1B1Zugu0gVGyA5leoXQJEzo6sDTQ95J8X0yFcdBNGNtw==} + sass-embedded@1.92.1: + resolution: {integrity: sha512-28YwLnF5atAhogt3E4hXzz/NB9dwKffyw08a7DEasLh94P7+aELkG3ENSHYCWB9QFN14hYNLfwr9ozUsPDhcDQ==} engines: {node: '>=16.0.0'} hasBin: true @@ -7593,8 +7599,8 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - sass@1.92.0: - resolution: {integrity: sha512-KDNI0BxgIRDAfJgzNm5wuy+4yOCIZyrUbjSpiU/JItfih+KGXAVefKL53MTml054MmBA3DDKIBMSI/7XLxZJ3A==} + sass@1.92.1: + resolution: {integrity: sha512-ffmsdbwqb3XeyR8jJR6KelIXARM9bFQe8A6Q3W4Klmwy5Ckd5gz7jgUNHo4UOqutU5Sk1DtKLbpDP0nLCg1xqQ==} engines: {node: '>=14.0.0'} hasBin: true @@ -7911,8 +7917,8 @@ packages: postcss-html: ^1.0.0 stylelint: '>=14.0.0' - stylelint-config-recess-order@7.2.0: - resolution: {integrity: sha512-3Y97dhsWkUHFKRLGNLF6LE5JuNB2EVAZKYJ41wBRK4gplYdk7eHhSIwE24hanu0AoNmv5534Djip70pE+y5qkA==} + stylelint-config-recess-order@7.3.0: + resolution: {integrity: sha512-1LZhQi/D6OljSLRKejMEzbZA8h0AKkJH7p2y+eValc9ltWRGVznjnZsNLVCOwYpKk7GlYMLNVYTc9WpA0W3TYQ==} peerDependencies: stylelint: '>=16.18' stylelint-order: '>=7' @@ -8019,8 +8025,8 @@ packages: tailwind-merge@3.3.1: resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} - tailwindcss@4.1.12: - resolution: {integrity: sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==} + tailwindcss@4.1.13: + resolution: {integrity: sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==} tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} @@ -9739,11 +9745,11 @@ snapshots: '@bufbuild/protobuf@2.5.2': {} - '@commitlint/cli@19.8.1(@types/node@24.3.0)(typescript@5.9.2)': + '@commitlint/cli@19.8.1(@types/node@24.3.1)(typescript@5.9.2)': dependencies: '@commitlint/format': 19.8.1 '@commitlint/lint': 19.8.1 - '@commitlint/load': 19.8.1(@types/node@24.3.0)(typescript@5.9.2) + '@commitlint/load': 19.8.1(@types/node@24.3.1)(typescript@5.9.2) '@commitlint/read': 19.8.1 '@commitlint/types': 19.8.1 tinyexec: 1.0.1 @@ -9790,7 +9796,7 @@ snapshots: '@commitlint/rules': 19.8.1 '@commitlint/types': 19.8.1 - '@commitlint/load@19.8.1(@types/node@24.3.0)(typescript@5.9.2)': + '@commitlint/load@19.8.1(@types/node@24.3.1)(typescript@5.9.2)': dependencies: '@commitlint/config-validator': 19.8.1 '@commitlint/execute-rule': 19.8.1 @@ -9798,7 +9804,7 @@ snapshots: '@commitlint/types': 19.8.1 chalk: 5.4.1 cosmiconfig: 9.0.0(typescript@5.9.2) - cosmiconfig-typescript-loader: 6.1.0(@types/node@24.3.0)(cosmiconfig@9.0.0(typescript@5.9.2))(typescript@5.9.2) + cosmiconfig-typescript-loader: 6.1.0(@types/node@24.3.1)(cosmiconfig@9.0.0(typescript@5.9.2))(typescript@5.9.2) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -10103,21 +10109,26 @@ snapshots: '@esbuild/win32-x64@0.25.0': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@9.34.0(jiti@2.5.1))': + '@eslint-community/eslint-utils@4.4.1(eslint@9.35.0(jiti@2.5.1))': dependencies: - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.7.0(eslint@9.34.0(jiti@2.5.1))': + '@eslint-community/eslint-utils@4.7.0(eslint@9.35.0(jiti@2.5.1))': dependencies: - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/eslint-utils@4.8.0(eslint@9.35.0(jiti@2.5.1))': + dependencies: + eslint: 9.35.0(jiti@2.5.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/compat@1.3.2(eslint@9.34.0(jiti@2.5.1))': + '@eslint/compat@1.3.2(eslint@9.35.0(jiti@2.5.1))': optionalDependencies: - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) '@eslint/config-array@0.21.0': dependencies: @@ -10147,7 +10158,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.34.0': {} + '@eslint/js@9.35.0': {} '@eslint/object-schema@2.1.6': {} @@ -10267,23 +10278,23 @@ snapshots: '@material/material-color-utilities@0.3.0': {} - '@microsoft/api-extractor-model@7.30.3(@types/node@24.3.0)': + '@microsoft/api-extractor-model@7.30.3(@types/node@24.3.1)': dependencies: '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.11.0(@types/node@24.3.0) + '@rushstack/node-core-library': 5.11.0(@types/node@24.3.1) transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor@7.51.0(@types/node@24.3.0)': + '@microsoft/api-extractor@7.51.0(@types/node@24.3.1)': dependencies: - '@microsoft/api-extractor-model': 7.30.3(@types/node@24.3.0) + '@microsoft/api-extractor-model': 7.30.3(@types/node@24.3.1) '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.11.0(@types/node@24.3.0) + '@rushstack/node-core-library': 5.11.0(@types/node@24.3.1) '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.15.0(@types/node@24.3.0) - '@rushstack/ts-command-line': 4.23.5(@types/node@24.3.0) + '@rushstack/terminal': 0.15.0(@types/node@24.3.1) + '@rushstack/ts-command-line': 4.23.5(@types/node@24.3.1) lodash: 4.17.21 minimatch: 3.0.8 resolve: 1.22.8 @@ -11029,7 +11040,7 @@ snapshots: '@rtsao/scc@1.1.0': {} - '@rushstack/node-core-library@5.11.0(@types/node@24.3.0)': + '@rushstack/node-core-library@5.11.0(@types/node@24.3.1)': dependencies: ajv: 8.13.0 ajv-draft-04: 1.0.0(ajv@8.13.0) @@ -11040,23 +11051,23 @@ snapshots: resolve: 1.22.8 semver: 7.5.4 optionalDependencies: - '@types/node': 24.3.0 + '@types/node': 24.3.1 '@rushstack/rig-package@0.5.3': dependencies: resolve: 1.22.8 strip-json-comments: 3.1.1 - '@rushstack/terminal@0.15.0(@types/node@24.3.0)': + '@rushstack/terminal@0.15.0(@types/node@24.3.1)': dependencies: - '@rushstack/node-core-library': 5.11.0(@types/node@24.3.0) + '@rushstack/node-core-library': 5.11.0(@types/node@24.3.1) supports-color: 8.1.1 optionalDependencies: - '@types/node': 24.3.0 + '@types/node': 24.3.1 - '@rushstack/ts-command-line@4.23.5(@types/node@24.3.0)': + '@rushstack/ts-command-line@4.23.5(@types/node@24.3.1)': dependencies: - '@rushstack/terminal': 0.15.0(@types/node@24.3.0) + '@rushstack/terminal': 0.15.0(@types/node@24.3.1) '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.2 @@ -11100,10 +11111,10 @@ snapshots: '@sindresorhus/is@4.6.0': {} - '@stylistic/eslint-plugin@2.11.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2)': + '@stylistic/eslint-plugin@2.11.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@typescript-eslint/utils': 8.41.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) - eslint: 9.34.0(jiti@2.5.1) + '@typescript-eslint/utils': 8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.5.1) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 @@ -11238,77 +11249,77 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tailwindcss/node@4.1.12': + '@tailwindcss/node@4.1.13': dependencies: '@jridgewell/remapping': 2.3.5 enhanced-resolve: 5.18.3 jiti: 2.5.1 lightningcss: 1.30.1 - magic-string: 0.30.17 + magic-string: 0.30.18 source-map-js: 1.2.1 - tailwindcss: 4.1.12 + tailwindcss: 4.1.13 - '@tailwindcss/oxide-android-arm64@4.1.12': + '@tailwindcss/oxide-android-arm64@4.1.13': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.12': + '@tailwindcss/oxide-darwin-arm64@4.1.13': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.12': + '@tailwindcss/oxide-darwin-x64@4.1.13': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.12': + '@tailwindcss/oxide-freebsd-x64@4.1.13': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.12': + '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.12': + '@tailwindcss/oxide-linux-arm64-musl@4.1.13': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.12': + '@tailwindcss/oxide-linux-x64-gnu@4.1.13': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.12': + '@tailwindcss/oxide-linux-x64-musl@4.1.13': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.12': + '@tailwindcss/oxide-wasm32-wasi@4.1.13': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.12': + '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.12': + '@tailwindcss/oxide-win32-x64-msvc@4.1.13': optional: true - '@tailwindcss/oxide@4.1.12': + '@tailwindcss/oxide@4.1.13': dependencies: detect-libc: 2.0.4 tar: 7.4.3 optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.12 - '@tailwindcss/oxide-darwin-arm64': 4.1.12 - '@tailwindcss/oxide-darwin-x64': 4.1.12 - '@tailwindcss/oxide-freebsd-x64': 4.1.12 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.12 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.12 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.12 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.12 - '@tailwindcss/oxide-linux-x64-musl': 4.1.12 - '@tailwindcss/oxide-wasm32-wasi': 4.1.12 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.12 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.12 + '@tailwindcss/oxide-android-arm64': 4.1.13 + '@tailwindcss/oxide-darwin-arm64': 4.1.13 + '@tailwindcss/oxide-darwin-x64': 4.1.13 + '@tailwindcss/oxide-freebsd-x64': 4.1.13 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.13 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.13 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.13 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.13 + '@tailwindcss/oxide-linux-x64-musl': 4.1.13 + '@tailwindcss/oxide-wasm32-wasi': 4.1.13 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.13 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.13 - '@tailwindcss/postcss@4.1.12': + '@tailwindcss/postcss@4.1.13': dependencies: '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.1.12 - '@tailwindcss/oxide': 4.1.12 + '@tailwindcss/node': 4.1.13 + '@tailwindcss/oxide': 4.1.13 postcss: 8.5.6 - tailwindcss: 4.1.12 + tailwindcss: 4.1.13 '@tanstack/history@1.131.2': {} @@ -11398,7 +11409,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.131.35(@tanstack/react-router@1.131.35(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))': + '@tanstack/router-plugin@1.131.35(@tanstack/react-router@1.131.35(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.3 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.3) @@ -11416,7 +11427,7 @@ snapshots: zod: 3.25.76 optionalDependencies: '@tanstack/react-router': 1.131.35(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - vite: 7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) + vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -11556,7 +11567,7 @@ snapshots: '@types/adm-zip@0.5.7': dependencies: - '@types/node': 24.3.0 + '@types/node': 24.3.1 '@types/argparse@1.0.38': {} @@ -11587,12 +11598,12 @@ snapshots: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 24.3.0 + '@types/node': 24.3.1 '@types/responselike': 1.0.3 '@types/conventional-commits-parser@5.0.0': dependencies: - '@types/node': 24.3.0 + '@types/node': 24.3.1 '@types/d3-array@3.2.1': {} @@ -11728,7 +11739,7 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 24.3.0 + '@types/node': 24.3.1 '@types/geojson@7946.0.14': {} @@ -11748,11 +11759,11 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 24.3.0 + '@types/node': 24.3.1 '@types/keyv@3.1.4': dependencies: - '@types/node': 24.3.0 + '@types/node': 24.3.1 '@types/lodash-es@4.17.12': dependencies: @@ -11768,7 +11779,7 @@ snapshots: '@types/node@16.18.108': {} - '@types/node@24.3.0': + '@types/node@24.3.1': dependencies: undici-types: 7.10.0 @@ -11798,9 +11809,9 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 24.3.0 + '@types/node': 24.3.1 - '@types/semver@7.7.0': {} + '@types/semver@7.7.1': {} '@types/unist@2.0.10': {} @@ -11816,18 +11827,18 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 24.3.0 + '@types/node': 24.3.1 optional: true - '@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) '@typescript-eslint/scope-manager': 8.42.0 - '@typescript-eslint/type-utils': 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/utils': 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.42.0 - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -11836,14 +11847,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@typescript-eslint/scope-manager': 8.42.0 '@typescript-eslint/types': 8.42.0 '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.42.0 debug: 4.4.1 - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -11884,13 +11895,13 @@ snapshots: dependencies: typescript: 5.9.2 - '@typescript-eslint/type-utils@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@typescript-eslint/types': 8.42.0 '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) debug: 4.4.1 - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) ts-api-utils: 2.1.0(typescript@5.9.2) typescript: 5.9.2 transitivePeerDependencies: @@ -11932,24 +11943,24 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.41.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/utils@8.41.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.34.0(jiti@2.5.1)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.35.0(jiti@2.5.1)) '@typescript-eslint/scope-manager': 8.41.0 '@typescript-eslint/types': 8.41.0 '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.34.0(jiti@2.5.1)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.35.0(jiti@2.5.1)) '@typescript-eslint/scope-manager': 8.42.0 '@typescript-eslint/types': 8.42.0 '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.9.2) - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -12025,7 +12036,7 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.10.1': optional: true - '@vitejs/plugin-legacy@7.2.1(terser@5.36.0)(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))': + '@vitejs/plugin-legacy@7.2.1(terser@5.36.0)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.0) @@ -12040,19 +12051,19 @@ snapshots: regenerator-runtime: 0.14.1 systemjs: 6.15.1 terser: 5.36.0 - vite: 7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) + vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react-swc@4.0.1(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))': + '@vitejs/plugin-react-swc@4.0.1(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.32 '@swc/core': 1.13.3 - vite: 7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) + vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@5.0.2(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))': + '@vitejs/plugin-react@5.0.2(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.3 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.3) @@ -12060,7 +12071,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.34 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) + vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -12743,9 +12754,9 @@ snapshots: core-js@3.45.1: {} - cosmiconfig-typescript-loader@6.1.0(@types/node@24.3.0)(cosmiconfig@9.0.0(typescript@5.9.2))(typescript@5.9.2): + cosmiconfig-typescript-loader@6.1.0(@types/node@24.3.1)(cosmiconfig@9.0.0(typescript@5.9.2))(typescript@5.9.2): dependencies: - '@types/node': 24.3.0 + '@types/node': 24.3.1 cosmiconfig: 9.0.0(typescript@5.9.2) jiti: 2.5.1 typescript: 5.9.2 @@ -13064,7 +13075,7 @@ snapshots: dependencies: mimic-response: 3.1.0 - dedent@1.6.0(babel-plugin-macros@3.1.0): + dedent@1.7.0(babel-plugin-macros@3.1.0): optionalDependencies: babel-plugin-macros: 3.1.0 @@ -13538,14 +13549,14 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-compat-utils@0.5.1(eslint@9.34.0(jiti@2.5.1)): + eslint-compat-utils@0.5.1(eslint@9.35.0(jiti@2.5.1)): dependencies: - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) semver: 7.7.2 - eslint-config-prettier@10.1.8(eslint@9.34.0(jiti@2.5.1)): + eslint-config-prettier@10.1.8(eslint@9.35.0(jiti@2.5.1)): dependencies: - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) eslint-import-context@0.1.9(unrs-resolver@1.10.1): dependencies: @@ -13554,9 +13565,9 @@ snapshots: optionalDependencies: unrs-resolver: 1.10.1 - eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1))): + eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))): dependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)) eslint-import-resolver-node@0.3.9: dependencies: @@ -13566,49 +13577,49 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.34.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) get-tsconfig: 4.10.1 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.14 unrs-resolver: 1.10.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)) - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.34.0(jiti@2.5.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.34.0(jiti@2.5.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) - eslint: 9.34.0(jiti@2.5.1) + '@typescript-eslint/parser': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-es-x@7.8.0(eslint@9.34.0(jiti@2.5.1)): + eslint-plugin-es-x@7.8.0(eslint@9.35.0(jiti@2.5.1)): dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.34.0(jiti@2.5.1)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.35.0(jiti@2.5.1)) '@eslint-community/regexpp': 4.12.1 - eslint: 9.34.0(jiti@2.5.1) - eslint-compat-utils: 0.5.1(eslint@9.34.0(jiti@2.5.1)) + eslint: 9.35.0(jiti@2.5.1) + eslint-compat-utils: 0.5.1(eslint@9.35.0(jiti@2.5.1)) eslint-plugin-html@8.1.3: dependencies: htmlparser2: 10.0.0 - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.34.0(jiti@2.5.1)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)): dependencies: '@typescript-eslint/types': 8.41.0 comment-parser: 1.4.1 debug: 4.4.1 - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) eslint-import-context: 0.1.9(unrs-resolver@1.10.1) is-glob: 4.0.3 minimatch: 9.0.5 @@ -13616,12 +13627,12 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.10.1 optionalDependencies: - '@typescript-eslint/utils': 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -13630,9 +13641,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.34.0(jiti@2.5.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -13644,18 +13655,18 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-n@17.21.3(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2): + eslint-plugin-n@17.21.3(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.34.0(jiti@2.5.1)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.35.0(jiti@2.5.1)) enhanced-resolve: 5.18.1 - eslint: 9.34.0(jiti@2.5.1) - eslint-plugin-es-x: 7.8.0(eslint@9.34.0(jiti@2.5.1)) + eslint: 9.35.0(jiti@2.5.1) + eslint-plugin-es-x: 7.8.0(eslint@9.35.0(jiti@2.5.1)) get-tsconfig: 4.10.1 globals: 15.15.0 globrex: 0.1.2 @@ -13665,37 +13676,37 @@ snapshots: transitivePeerDependencies: - typescript - eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1))(prettier@3.6.2): + eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(prettier@3.6.2): dependencies: - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) prettier: 3.6.2 prettier-linter-helpers: 1.0.0 synckit: 0.11.8 optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@9.34.0(jiti@2.5.1)) + eslint-config-prettier: 10.1.8(eslint@9.35.0(jiti@2.5.1)) - eslint-plugin-promise@7.2.1(eslint@9.34.0(jiti@2.5.1)): + eslint-plugin-promise@7.2.1(eslint@9.35.0(jiti@2.5.1)): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.34.0(jiti@2.5.1)) - eslint: 9.34.0(jiti@2.5.1) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.35.0(jiti@2.5.1)) + eslint: 9.35.0(jiti@2.5.1) - eslint-plugin-react-compiler@19.1.0-rc.2(eslint@9.34.0(jiti@2.5.1)): + eslint-plugin-react-compiler@19.1.0-rc.2(eslint@9.35.0(jiti@2.5.1)): dependencies: '@babel/core': 7.26.10 '@babel/parser': 7.27.0 '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.26.10) - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) hermes-parser: 0.25.1 zod: 3.24.4 zod-validation-error: 3.3.1(zod@3.24.4) transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks@5.2.0(eslint@9.34.0(jiti@2.5.1)): + eslint-plugin-react-hooks@5.2.0(eslint@9.35.0(jiti@2.5.1)): dependencies: - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) - eslint-plugin-react@7.37.5(eslint@9.34.0(jiti@2.5.1)): + eslint-plugin-react@7.37.5(eslint@9.35.0(jiti@2.5.1)): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -13703,7 +13714,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.34.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.5.1) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -13728,15 +13739,15 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.34.0(jiti@2.5.1): + eslint@9.35.0(jiti@2.5.1): dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.34.0(jiti@2.5.1)) + '@eslint-community/eslint-utils': 4.8.0(eslint@9.35.0(jiti@2.5.1)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.21.0 '@eslint/config-helpers': 0.3.1 '@eslint/core': 0.15.2 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.34.0 + '@eslint/js': 9.35.0 '@eslint/plugin-kit': 0.3.5 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 @@ -14838,10 +14849,10 @@ snapshots: kind-of@6.0.3: {} - knip@5.63.1(@types/node@24.3.0)(typescript@5.9.2): + knip@5.63.1(@types/node@24.3.1)(typescript@5.9.2): dependencies: '@nodelib/fs.walk': 1.2.8 - '@types/node': 24.3.0 + '@types/node': 24.3.1 fast-glob: 3.3.3 formatly: 0.3.0 jiti: 2.5.1 @@ -15451,20 +15462,20 @@ snapshots: sax: 1.3.0 optional: true - neostandard@0.12.2(@typescript-eslint/utils@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2): + neostandard@0.12.2(@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): dependencies: '@humanwhocodes/gitignore-to-minimatch': 1.0.2 - '@stylistic/eslint-plugin': 2.11.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) - eslint: 9.34.0(jiti@2.5.1) - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.34.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.34.0(jiti@2.5.1)) - eslint-plugin-n: 17.21.3(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) - eslint-plugin-promise: 7.2.1(eslint@9.34.0(jiti@2.5.1)) - eslint-plugin-react: 7.37.5(eslint@9.34.0(jiti@2.5.1)) + '@stylistic/eslint-plugin': 2.11.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.5.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)) + eslint-plugin-n: 17.21.3(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint-plugin-promise: 7.2.1(eslint@9.35.0(jiti@2.5.1)) + eslint-plugin-react: 7.37.5(eslint@9.35.0(jiti@2.5.1)) find-up: 5.0.0 globals: 15.15.0 peowly: 1.3.2 - typescript-eslint: 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + typescript-eslint: 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) transitivePeerDependencies: - '@typescript-eslint/utils' - eslint-import-resolver-node @@ -16394,65 +16405,65 @@ snapshots: safer-buffer@2.1.2: {} - sass-embedded-all-unknown@1.92.0: + sass-embedded-all-unknown@1.92.1: dependencies: - sass: 1.92.0 + sass: 1.92.1 optional: true - sass-embedded-android-arm64@1.92.0: + sass-embedded-android-arm64@1.92.1: optional: true - sass-embedded-android-arm@1.92.0: + sass-embedded-android-arm@1.92.1: optional: true - sass-embedded-android-riscv64@1.92.0: + sass-embedded-android-riscv64@1.92.1: optional: true - sass-embedded-android-x64@1.92.0: + sass-embedded-android-x64@1.92.1: optional: true - sass-embedded-darwin-arm64@1.92.0: + sass-embedded-darwin-arm64@1.92.1: optional: true - sass-embedded-darwin-x64@1.92.0: + sass-embedded-darwin-x64@1.92.1: optional: true - sass-embedded-linux-arm64@1.92.0: + sass-embedded-linux-arm64@1.92.1: optional: true - sass-embedded-linux-arm@1.92.0: + sass-embedded-linux-arm@1.92.1: optional: true - sass-embedded-linux-musl-arm64@1.92.0: + sass-embedded-linux-musl-arm64@1.92.1: optional: true - sass-embedded-linux-musl-arm@1.92.0: + sass-embedded-linux-musl-arm@1.92.1: optional: true - sass-embedded-linux-musl-riscv64@1.92.0: + sass-embedded-linux-musl-riscv64@1.92.1: optional: true - sass-embedded-linux-musl-x64@1.92.0: + sass-embedded-linux-musl-x64@1.92.1: optional: true - sass-embedded-linux-riscv64@1.92.0: + sass-embedded-linux-riscv64@1.92.1: optional: true - sass-embedded-linux-x64@1.92.0: + sass-embedded-linux-x64@1.92.1: optional: true - sass-embedded-unknown-all@1.92.0: + sass-embedded-unknown-all@1.92.1: dependencies: - sass: 1.92.0 + sass: 1.92.1 optional: true - sass-embedded-win32-arm64@1.92.0: + sass-embedded-win32-arm64@1.92.1: optional: true - sass-embedded-win32-x64@1.92.0: + sass-embedded-win32-x64@1.92.1: optional: true - sass-embedded@1.92.0: + sass-embedded@1.92.1: dependencies: '@bufbuild/protobuf': 2.5.2 buffer-builder: 0.2.0 @@ -16463,24 +16474,24 @@ snapshots: sync-child-process: 1.0.2 varint: 6.0.0 optionalDependencies: - sass-embedded-all-unknown: 1.92.0 - sass-embedded-android-arm: 1.92.0 - sass-embedded-android-arm64: 1.92.0 - sass-embedded-android-riscv64: 1.92.0 - sass-embedded-android-x64: 1.92.0 - sass-embedded-darwin-arm64: 1.92.0 - sass-embedded-darwin-x64: 1.92.0 - sass-embedded-linux-arm: 1.92.0 - sass-embedded-linux-arm64: 1.92.0 - sass-embedded-linux-musl-arm: 1.92.0 - sass-embedded-linux-musl-arm64: 1.92.0 - sass-embedded-linux-musl-riscv64: 1.92.0 - sass-embedded-linux-musl-x64: 1.92.0 - sass-embedded-linux-riscv64: 1.92.0 - sass-embedded-linux-x64: 1.92.0 - sass-embedded-unknown-all: 1.92.0 - sass-embedded-win32-arm64: 1.92.0 - sass-embedded-win32-x64: 1.92.0 + sass-embedded-all-unknown: 1.92.1 + sass-embedded-android-arm: 1.92.1 + sass-embedded-android-arm64: 1.92.1 + sass-embedded-android-riscv64: 1.92.1 + sass-embedded-android-x64: 1.92.1 + sass-embedded-darwin-arm64: 1.92.1 + sass-embedded-darwin-x64: 1.92.1 + sass-embedded-linux-arm: 1.92.1 + sass-embedded-linux-arm64: 1.92.1 + sass-embedded-linux-musl-arm: 1.92.1 + sass-embedded-linux-musl-arm64: 1.92.1 + sass-embedded-linux-musl-riscv64: 1.92.1 + sass-embedded-linux-musl-x64: 1.92.1 + sass-embedded-linux-riscv64: 1.92.1 + sass-embedded-linux-x64: 1.92.1 + sass-embedded-unknown-all: 1.92.1 + sass-embedded-win32-arm64: 1.92.1 + sass-embedded-win32-x64: 1.92.1 sass@1.83.0: dependencies: @@ -16490,7 +16501,7 @@ snapshots: optionalDependencies: '@parcel/watcher': 2.4.1 - sass@1.92.0: + sass@1.92.1: dependencies: chokidar: 4.0.0 immutable: 5.0.2 @@ -16830,7 +16841,7 @@ snapshots: postcss-html: 1.8.0 stylelint: 16.23.1(typescript@5.9.2) - stylelint-config-recess-order@7.2.0(stylelint-order@7.0.0(stylelint@16.23.1(typescript@5.9.2)))(stylelint@16.23.1(typescript@5.9.2)): + stylelint-config-recess-order@7.3.0(stylelint-order@7.0.0(stylelint@16.23.1(typescript@5.9.2)))(stylelint@16.23.1(typescript@5.9.2)): dependencies: stylelint: 16.23.1(typescript@5.9.2) stylelint-order: 7.0.0(stylelint@16.23.1(typescript@5.9.2)) @@ -16982,7 +16993,7 @@ snapshots: tailwind-merge@3.3.1: {} - tailwindcss@4.1.12: {} + tailwindcss@4.1.13: {} tapable@2.2.1: {} @@ -17185,13 +17196,13 @@ snapshots: dependencies: is-typedarray: 1.0.0 - typescript-eslint@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2): + typescript-eslint@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/parser': 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.42.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) - eslint: 9.34.0(jiti@2.5.1) + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -17480,9 +17491,9 @@ snapshots: - rollup - supports-color - vite-plugin-dts@4.5.4(@types/node@24.3.0)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)): + vite-plugin-dts@4.5.4(@types/node@24.3.1)(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)): dependencies: - '@microsoft/api-extractor': 7.51.0(@types/node@24.3.0) + '@microsoft/api-extractor': 7.51.0(@types/node@24.3.1) '@rollup/pluginutils': 5.1.4(rollup@4.46.2) '@volar/typescript': 2.4.11 '@vue/language-core': 2.2.0(typescript@5.9.2) @@ -17493,13 +17504,13 @@ snapshots: magic-string: 0.30.17 typescript: 5.9.2 optionalDependencies: - vite: 7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) + vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - rollup - supports-color - vite-plugin-html@3.2.2(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)): + vite-plugin-html@3.2.2(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)): dependencies: '@rollup/pluginutils': 4.2.1 colorette: 2.0.20 @@ -17513,39 +17524,39 @@ snapshots: html-minifier-terser: 6.1.0 node-html-parser: 5.4.2 pathe: 0.2.0 - vite: 7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) + vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) - vite-plugin-sass-dts@1.3.31(postcss@8.5.6)(prettier@3.6.2)(sass-embedded@1.92.0)(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)): + vite-plugin-sass-dts@1.3.31(postcss@8.5.6)(prettier@3.6.2)(sass-embedded@1.92.1)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)): dependencies: postcss: 8.5.6 postcss-js: 4.0.1(postcss@8.5.6) prettier: 3.6.2 - sass-embedded: 1.92.0 - vite: 7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) + sass-embedded: 1.92.1 + vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) - vite-plugin-svgr@4.5.0(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)): + vite-plugin-svgr@4.5.0(rollup@4.46.2)(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)): dependencies: '@rollup/pluginutils': 5.2.0(rollup@4.46.2) '@svgr/core': 8.1.0(typescript@5.9.2) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.2)) - vite: 7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) + vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)): + vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1)): dependencies: debug: 4.3.7 globrex: 0.1.2 tsconfck: 3.0.3(typescript@5.9.2) optionalDependencies: - vite: 7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) + vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1) transitivePeerDependencies: - supports-color - typescript - vite@7.1.4(@types/node@24.3.0)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.0)(sass@1.92.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1): + vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.5)(yaml@2.8.1): dependencies: esbuild: 0.25.0 fdir: 6.5.0(picomatch@4.0.3) @@ -17554,13 +17565,13 @@ snapshots: rollup: 4.46.2 tinyglobby: 0.2.14 optionalDependencies: - '@types/node': 24.3.0 + '@types/node': 24.3.1 fsevents: 2.3.3 jiti: 2.5.1 less: 4.2.0 lightningcss: 1.30.1 - sass: 1.92.0 - sass-embedded: 1.92.0 + sass: 1.92.1 + sass-embedded: 1.92.1 stylus: 0.62.0 terser: 5.36.0 tsx: 4.20.5 diff --git a/clash-nyanpasu/scripts/package.json b/clash-nyanpasu/scripts/package.json index bfb1964a0d..79aec3e5c0 100644 --- a/clash-nyanpasu/scripts/package.json +++ b/clash-nyanpasu/scripts/package.json @@ -5,7 +5,7 @@ "dependencies": { "@actions/github": "6.0.1", "@types/figlet": "1.7.0", - "@types/semver": "7.7.0", + "@types/semver": "7.7.1", "figlet": "1.8.2", "filesize": "11.0.2", "p-retry": "7.0.0", diff --git a/geoip/plugin/maxmind/common_out.go b/geoip/plugin/maxmind/common_out.go index bfd41aaa32..01f10fc011 100644 --- a/geoip/plugin/maxmind/common_out.go +++ b/geoip/plugin/maxmind/common_out.go @@ -20,6 +20,17 @@ var ( defaultIPInfoOutputDir = filepath.Join("./", "output", "ipinfo") ) +// Reference: https://ipinfo.io/lite +type ipInfoLite struct { + ASN string `maxminddb:"asn"` + ASName string `maxminddb:"as_name"` + ASDomain string `maxminddb:"as_domain"` + Continent string `maxminddb:"continent"` + ContinentCode string `maxminddb:"continent_code"` + Country string `maxminddb:"country"` + CountryCode string `maxminddb:"country_code"` +} + func newGeoLite2CountryMMDBOut(iType string, iDesc string, action lib.Action, data json.RawMessage) (lib.OutputConverter, error) { var tmp struct { OutputName string `json:"outputName"` @@ -144,19 +155,16 @@ func (g *GeoLite2CountryMMDBOut) GetExtraInfo() (map[string]any, error) { } case TypeIPInfoCountryMMDBOut: - record := struct { - Continent string `maxminddb:"continent"` - ContinentName string `maxminddb:"continent_name"` - Country string `maxminddb:"country"` - CountryName string `maxminddb:"country_name"` - }{} - + var record ipInfoLite _, err := networks.Network(&record) if err != nil { return nil, err } - countryCode := strings.ToUpper(strings.TrimSpace(record.Country)) + countryCode := strings.ToUpper(strings.TrimSpace(record.CountryCode)) if _, found := infoList[countryCode]; !found { + record.ASN = "" + record.ASName = "" + record.ASDomain = "" infoList[countryCode] = record } diff --git a/geoip/plugin/maxmind/maxmind_country_mmdb_in.go b/geoip/plugin/maxmind/maxmind_country_mmdb_in.go index 7578ba238e..ab8be53fb7 100644 --- a/geoip/plugin/maxmind/maxmind_country_mmdb_in.go +++ b/geoip/plugin/maxmind/maxmind_country_mmdb_in.go @@ -127,14 +127,12 @@ func (g *GeoLite2CountryMMDBIn) generateEntries(content []byte, entries map[stri } case TypeIPInfoCountryMMDBIn: - record := struct { - Country string `maxminddb:"country"` - }{} + var record ipInfoLite subnet, err = networks.Network(&record) if err != nil { return err } - name = strings.ToUpper(strings.TrimSpace(record.Country)) + name = strings.ToUpper(strings.TrimSpace(record.CountryCode)) default: return lib.ErrNotSupportedFormat diff --git a/geoip/plugin/maxmind/maxmind_country_mmdb_out.go b/geoip/plugin/maxmind/maxmind_country_mmdb_out.go index cca77632c7..7cba249eed 100644 --- a/geoip/plugin/maxmind/maxmind_country_mmdb_out.go +++ b/geoip/plugin/maxmind/maxmind_country_mmdb_out.go @@ -70,8 +70,8 @@ func (g *GeoLite2CountryMMDBOut) Output(container lib.Container) error { dbDesc = "Customized DB-IP Country Lite database" case TypeIPInfoCountryMMDBOut: - dbName = "IPInfo-Country" - dbDesc = "Customized IPInfo Country database" + dbName = "IPInfo-Lite" + dbDesc = "Customized IPInfo Lite database" recordSize = 32 } @@ -199,7 +199,7 @@ func (g *GeoLite2CountryMMDBOut) marshalData(writer *mmdbwriter.Tree, entry *lib case TypeIPInfoCountryMMDBOut: record = mmdbtype.Map{ - "country": mmdbtype.String(entry.GetName()), + "country_code": mmdbtype.String(entry.GetName()), } default: @@ -339,25 +339,22 @@ func (g *GeoLite2CountryMMDBOut) marshalData(writer *mmdbwriter.Tree, entry *lib } case TypeIPInfoCountryMMDBOut: - info, found := extraInfo[entry.GetName()].(struct { - Continent string `maxminddb:"continent"` - ContinentName string `maxminddb:"continent_name"` - Country string `maxminddb:"country"` - CountryName string `maxminddb:"country_name"` - }) - + info, found := extraInfo[entry.GetName()].(ipInfoLite) if !found { log.Printf("⚠️ [type %s | action %s] not found extra info for list %s\n", g.Type, g.Action, entry.GetName()) record = mmdbtype.Map{ - "country": mmdbtype.String(entry.GetName()), + "country_code": mmdbtype.String(entry.GetName()), } } else { record = mmdbtype.Map{ + "as_domain": mmdbtype.String(info.ASDomain), + "as_name": mmdbtype.String(info.ASName), + "asn": mmdbtype.String(info.ASN), "continent": mmdbtype.String(info.Continent), - "continent_name": mmdbtype.String(info.ContinentName), - "country": mmdbtype.String(entry.GetName()), - "country_name": mmdbtype.String(info.CountryName), + "continent_code": mmdbtype.String(info.ContinentCode), + "country": mmdbtype.String(info.Country), + "country_code": mmdbtype.String(entry.GetName()), } } diff --git a/lede/include/kernel-5.10 b/lede/include/kernel-5.10 index 41776ac0c9..bc55c8f446 100644 --- a/lede/include/kernel-5.10 +++ b/lede/include/kernel-5.10 @@ -1,2 +1,2 @@ -LINUX_VERSION-5.10 = .241 -LINUX_KERNEL_HASH-5.10.241 = 08c1e982064c81f8445a8fff2293d430c716c11fd3185606b8275718d696d8d6 +LINUX_VERSION-5.10 = .242 +LINUX_KERNEL_HASH-5.10.242 = bc3ae7003174e26c9a39534cfb8d66cee1a0ba6e1dd0381a9fe092f9de6ba9cd diff --git a/lede/include/kernel-5.15 b/lede/include/kernel-5.15 index 43cc235a52..b374d5492f 100644 --- a/lede/include/kernel-5.15 +++ b/lede/include/kernel-5.15 @@ -1,2 +1,2 @@ -LINUX_VERSION-5.15 = .190 -LINUX_KERNEL_HASH-5.15.190 = 62b814f1a48e1d67764a28611f23ca1f1ce1084ad7f1d319acc05720a9a68604 +LINUX_VERSION-5.15 = .191 +LINUX_KERNEL_HASH-5.15.191 = 7a2db3ac34a3edb6f497204cc287497c29bb3218fdb7876951f8bceac46e924e diff --git a/lede/include/kernel-5.4 b/lede/include/kernel-5.4 index 06171ca99a..d688e2a774 100644 --- a/lede/include/kernel-5.4 +++ b/lede/include/kernel-5.4 @@ -1,2 +1,2 @@ -LINUX_VERSION-5.4 = .297 -LINUX_KERNEL_HASH-5.4.297 = f10cfcea7acf7588087d7cc17ebeeb7d3ff783c040536698c544eed7c5e8a841 +LINUX_VERSION-5.4 = .298 +LINUX_KERNEL_HASH-5.4.298 = 01163bed1abadc1e5e6480f0d694c360281cbff3446023c2e015f1e24504e4e6 diff --git a/lede/include/kernel-6.1 b/lede/include/kernel-6.1 index 86197c0983..b3f08345c6 100644 --- a/lede/include/kernel-6.1 +++ b/lede/include/kernel-6.1 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.1 = .149 -LINUX_KERNEL_HASH-6.1.149 = c4e906b8d39a5866d25e06371d4de4454fbfaaeb67979a04e4137e807877be39 +LINUX_VERSION-6.1 = .150 +LINUX_KERNEL_HASH-6.1.150 = 001bffcc08e2b544fb507c0588f9270f8b5b1138508a4be1205492e3c57824ef diff --git a/lede/include/kernel-6.12 b/lede/include/kernel-6.12 index e28a8c4870..6108288d11 100644 --- a/lede/include/kernel-6.12 +++ b/lede/include/kernel-6.12 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.12 = .44 -LINUX_KERNEL_HASH-6.12.44 = b650210ed3027b224969d148aa377452a9aad3ae7f2851abedd31adfef16bdae +LINUX_VERSION-6.12 = .45 +LINUX_KERNEL_HASH-6.12.45 = 8f95a8549cfbdfb89c1181a1f55a971f04dfcd629508a2ed70b777ab92f9db3e diff --git a/lede/include/kernel-6.6 b/lede/include/kernel-6.6 index 8a2014fcc6..70decb6786 100644 --- a/lede/include/kernel-6.6 +++ b/lede/include/kernel-6.6 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.6 = .103 -LINUX_KERNEL_HASH-6.6.103 = d288dd38c3e62ba576ba6b3ad2a84cfba65cd43b702f6c50d1f701aee942b18e +LINUX_VERSION-6.6 = .104 +LINUX_KERNEL_HASH-6.6.104 = 2a772f9d661afabaaddcdfd1116239acb2d943377aceab9e0baed2b7a915e36a diff --git a/lede/target/linux/generic/backport-5.4/880-v5.17-net-skb-introduce-kfree_skb_reason.patch b/lede/target/linux/generic/backport-5.4/880-v5.17-net-skb-introduce-kfree_skb_reason.patch new file mode 100644 index 0000000000..e08ebe1136 --- /dev/null +++ b/lede/target/linux/generic/backport-5.4/880-v5.17-net-skb-introduce-kfree_skb_reason.patch @@ -0,0 +1,216 @@ +From c504e5c2f9648a1e5c2be01e8c3f59d394192bd3 Mon Sep 17 00:00:00 2001 +From: Menglong Dong +Date: Sun, 9 Jan 2022 14:36:26 +0800 +Subject: [PATCH] net: skb: introduce kfree_skb_reason() + +Introduce the interface kfree_skb_reason(), which is able to pass +the reason why the skb is dropped to 'kfree_skb' tracepoint. + +Add the 'reason' field to 'trace_kfree_skb', therefor user can get +more detail information about abnormal skb with 'drop_monitor' or +eBPF. + +All drop reasons are defined in the enum 'skb_drop_reason', and +they will be print as string in 'kfree_skb' tracepoint in format +of 'reason: XXX'. + +( Maybe the reasons should be defined in a uapi header file, so that +user space can use them? ) + +Signed-off-by: Menglong Dong +Signed-off-by: Jakub Kicinski +--- + include/linux/skbuff.h | 23 ++++++++++++++++++++++- + include/trace/events/skb.h | 36 +++++++++++++++++++++++++++++------- + net/core/dev.c | 3 ++- + net/core/drop_monitor.c | 10 +++++++--- + net/core/skbuff.c | 12 +++++++----- + 5 files changed, 67 insertions(+), 17 deletions(-) + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 642acb0d1646b7..ef0870abc791c9 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -305,6 +305,17 @@ struct sk_buff_head { + + struct sk_buff; + ++/* The reason of skb drop, which is used in kfree_skb_reason(). ++ * en...maybe they should be splited by group? ++ * ++ * Each item here should also be in 'TRACE_SKB_DROP_REASON', which is ++ * used to translate the reason to string. ++ */ ++enum skb_drop_reason { ++ SKB_DROP_REASON_NOT_SPECIFIED, ++ SKB_DROP_REASON_MAX, ++}; ++ + /* To allow 64K frame to be packed as single skb without frag_list we + * require 64K/PAGE_SIZE pages plus 1 additional page to allow for + * buffers which do not start on a page boundary. +@@ -1085,8 +1096,18 @@ static inline bool skb_unref(struct sk_buff *skb) + return true; + } + ++void kfree_skb_reason(struct sk_buff *skb, enum skb_drop_reason reason); ++ ++/** ++ * kfree_skb - free an sk_buff with 'NOT_SPECIFIED' reason ++ * @skb: buffer to free ++ */ ++static inline void kfree_skb(struct sk_buff *skb) ++{ ++ kfree_skb_reason(skb, SKB_DROP_REASON_NOT_SPECIFIED); ++} ++ + void skb_release_head_state(struct sk_buff *skb); +-void kfree_skb(struct sk_buff *skb); + void kfree_skb_list(struct sk_buff *segs); + void skb_dump(const char *level, const struct sk_buff *skb, bool full_pkt); + void skb_tx_error(struct sk_buff *skb); +diff --git a/include/trace/events/skb.h b/include/trace/events/skb.h +index 9e92f22eb086c2..294c61bbe44b6e 100644 +--- a/include/trace/events/skb.h ++++ b/include/trace/events/skb.h +@@ -9,29 +9,51 @@ + #include + #include + ++#define TRACE_SKB_DROP_REASON \ ++ EM(SKB_DROP_REASON_NOT_SPECIFIED, NOT_SPECIFIED) \ ++ EMe(SKB_DROP_REASON_MAX, MAX) ++ ++#undef EM ++#undef EMe ++ ++#define EM(a, b) TRACE_DEFINE_ENUM(a); ++#define EMe(a, b) TRACE_DEFINE_ENUM(a); ++ ++TRACE_SKB_DROP_REASON ++ ++#undef EM ++#undef EMe ++#define EM(a, b) { a, #b }, ++#define EMe(a, b) { a, #b } ++ + /* + * Tracepoint for free an sk_buff: + */ + TRACE_EVENT(kfree_skb, + +- TP_PROTO(struct sk_buff *skb, void *location), ++ TP_PROTO(struct sk_buff *skb, void *location, ++ enum skb_drop_reason reason), + +- TP_ARGS(skb, location), ++ TP_ARGS(skb, location, reason), + + TP_STRUCT__entry( +- __field( void *, skbaddr ) +- __field( void *, location ) +- __field( unsigned short, protocol ) ++ __field(void *, skbaddr) ++ __field(void *, location) ++ __field(unsigned short, protocol) ++ __field(enum skb_drop_reason, reason) + ), + + TP_fast_assign( + __entry->skbaddr = skb; + __entry->location = location; + __entry->protocol = ntohs(skb->protocol); ++ __entry->reason = reason; + ), + +- TP_printk("skbaddr=%p protocol=%u location=%p", +- __entry->skbaddr, __entry->protocol, __entry->location) ++ TP_printk("skbaddr=%p protocol=%u location=%p reason: %s", ++ __entry->skbaddr, __entry->protocol, __entry->location, ++ __print_symbolic(__entry->reason, ++ TRACE_SKB_DROP_REASON)) + ); + + TRACE_EVENT(consume_skb, +diff --git a/net/core/dev.c b/net/core/dev.c +index 83a4089990a0af..84a0d9542fe943 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4899,7 +4899,8 @@ static __latent_entropy void net_tx_action(struct softirq_action *h) + if (likely(get_kfree_skb_cb(skb)->reason == SKB_REASON_CONSUMED)) + trace_consume_skb(skb); + else +- trace_kfree_skb(skb, net_tx_action); ++ trace_kfree_skb(skb, net_tx_action, ++ SKB_DROP_REASON_NOT_SPECIFIED); + + if (skb->fclone != SKB_FCLONE_UNAVAILABLE) + __kfree_skb(skb); +diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c +index 3d0ab2eec91667..7b288a121a41a7 100644 +--- a/net/core/drop_monitor.c ++++ b/net/core/drop_monitor.c +@@ -110,7 +110,8 @@ static u32 net_dm_queue_len = 1000; + + struct net_dm_alert_ops { + void (*kfree_skb_probe)(void *ignore, struct sk_buff *skb, +- void *location); ++ void *location, ++ enum skb_drop_reason reason); + void (*napi_poll_probe)(void *ignore, struct napi_struct *napi, + int work, int budget); + void (*work_item_func)(struct work_struct *work); +@@ -262,7 +263,9 @@ static void trace_drop_common(struct sk_buff *skb, void *location) + spin_unlock_irqrestore(&data->lock, flags); + } + +-static void trace_kfree_skb_hit(void *ignore, struct sk_buff *skb, void *location) ++static void trace_kfree_skb_hit(void *ignore, struct sk_buff *skb, ++ void *location, ++ enum skb_drop_reason reason) + { + trace_drop_common(skb, location); + } +@@ -490,7 +493,8 @@ static const struct net_dm_alert_ops net_dm_alert_summary_ops = { + + static void net_dm_packet_trace_kfree_skb_hit(void *ignore, + struct sk_buff *skb, +- void *location) ++ void *location, ++ enum skb_drop_reason reason) + { + ktime_t tstamp = ktime_get_real(); + struct per_cpu_dm_data *data; +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index e514a36bcffcc8..0118f0afaa4fce 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -759,21 +759,23 @@ void __kfree_skb(struct sk_buff *skb) + EXPORT_SYMBOL(__kfree_skb); + + /** +- * kfree_skb - free an sk_buff ++ * kfree_skb_reason - free an sk_buff with special reason + * @skb: buffer to free ++ * @reason: reason why this skb is dropped + * + * Drop a reference to the buffer and free it if the usage count has +- * hit zero. ++ * hit zero. Meanwhile, pass the drop reason to 'kfree_skb' ++ * tracepoint. + */ +-void kfree_skb(struct sk_buff *skb) ++void kfree_skb_reason(struct sk_buff *skb, enum skb_drop_reason reason) + { + if (!skb_unref(skb)) + return; + +- trace_kfree_skb(skb, __builtin_return_address(0)); ++ trace_kfree_skb(skb, __builtin_return_address(0), reason); + __kfree_skb(skb); + } +-EXPORT_SYMBOL(kfree_skb); ++EXPORT_SYMBOL(kfree_skb_reason); + + void kfree_skb_list(struct sk_buff *segs) + { diff --git a/lede/target/linux/generic/backport-6.12/626-v6.17-net-ipv4-fix-regression-in-local-broadcast-routes.patch b/lede/target/linux/generic/backport-6.12/626-v6.17-net-ipv4-fix-regression-in-local-broadcast-routes.patch deleted file mode 100644 index 3653ccec6c..0000000000 --- a/lede/target/linux/generic/backport-6.12/626-v6.17-net-ipv4-fix-regression-in-local-broadcast-routes.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 5189446ba995556eaa3755a6e875bc06675b88bd Mon Sep 17 00:00:00 2001 -From: Oscar Maes -Date: Wed, 27 Aug 2025 08:23:21 +0200 -Subject: [PATCH] net: ipv4: fix regression in local-broadcast routes - -Commit 9e30ecf23b1b ("net: ipv4: fix incorrect MTU in broadcast routes") -introduced a regression where local-broadcast packets would have their -gateway set in __mkroute_output, which was caused by fi = NULL being -removed. - -Fix this by resetting the fib_info for local-broadcast packets. This -preserves the intended changes for directed-broadcast packets. - -Cc: stable@vger.kernel.org -Fixes: 9e30ecf23b1b ("net: ipv4: fix incorrect MTU in broadcast routes") -Reported-by: Brett A C Sheffield -Closes: https://lore.kernel.org/regressions/20250822165231.4353-4-bacs@librecast.net -Signed-off-by: Oscar Maes -Reviewed-by: David Ahern -Link: https://patch.msgid.link/20250827062322.4807-1-oscmaes92@gmail.com -Signed-off-by: Paolo Abeni ---- - net/ipv4/route.c | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - ---- a/net/ipv4/route.c -+++ b/net/ipv4/route.c -@@ -2532,12 +2532,16 @@ static struct rtable *__mkroute_output(c - !netif_is_l3_master(dev_out)) - return ERR_PTR(-EINVAL); - -- if (ipv4_is_lbcast(fl4->daddr)) -+ if (ipv4_is_lbcast(fl4->daddr)) { - type = RTN_BROADCAST; -- else if (ipv4_is_multicast(fl4->daddr)) -+ -+ /* reset fi to prevent gateway resolution */ -+ fi = NULL; -+ } else if (ipv4_is_multicast(fl4->daddr)) { - type = RTN_MULTICAST; -- else if (ipv4_is_zeronet(fl4->daddr)) -+ } else if (ipv4_is_zeronet(fl4->daddr)) { - return ERR_PTR(-EINVAL); -+ } - - if (dev_out->flags & IFF_LOOPBACK) - flags |= RTCF_LOCAL; diff --git a/lede/target/linux/generic/backport-6.6/626-v6.17-net-ipv4-fix-regression-in-local-broadcast-routes.patch b/lede/target/linux/generic/backport-6.6/626-v6.17-net-ipv4-fix-regression-in-local-broadcast-routes.patch deleted file mode 100644 index e250c2d88f..0000000000 --- a/lede/target/linux/generic/backport-6.6/626-v6.17-net-ipv4-fix-regression-in-local-broadcast-routes.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 5189446ba995556eaa3755a6e875bc06675b88bd Mon Sep 17 00:00:00 2001 -From: Oscar Maes -Date: Wed, 27 Aug 2025 08:23:21 +0200 -Subject: [PATCH] net: ipv4: fix regression in local-broadcast routes - -Commit 9e30ecf23b1b ("net: ipv4: fix incorrect MTU in broadcast routes") -introduced a regression where local-broadcast packets would have their -gateway set in __mkroute_output, which was caused by fi = NULL being -removed. - -Fix this by resetting the fib_info for local-broadcast packets. This -preserves the intended changes for directed-broadcast packets. - -Cc: stable@vger.kernel.org -Fixes: 9e30ecf23b1b ("net: ipv4: fix incorrect MTU in broadcast routes") -Reported-by: Brett A C Sheffield -Closes: https://lore.kernel.org/regressions/20250822165231.4353-4-bacs@librecast.net -Signed-off-by: Oscar Maes -Reviewed-by: David Ahern -Link: https://patch.msgid.link/20250827062322.4807-1-oscmaes92@gmail.com -Signed-off-by: Paolo Abeni ---- - net/ipv4/route.c | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - ---- a/net/ipv4/route.c -+++ b/net/ipv4/route.c -@@ -2547,12 +2547,16 @@ static struct rtable *__mkroute_output(c - !netif_is_l3_master(dev_out)) - return ERR_PTR(-EINVAL); - -- if (ipv4_is_lbcast(fl4->daddr)) -+ if (ipv4_is_lbcast(fl4->daddr)) { - type = RTN_BROADCAST; -- else if (ipv4_is_multicast(fl4->daddr)) -+ -+ /* reset fi to prevent gateway resolution */ -+ fi = NULL; -+ } else if (ipv4_is_multicast(fl4->daddr)) { - type = RTN_MULTICAST; -- else if (ipv4_is_zeronet(fl4->daddr)) -+ } else if (ipv4_is_zeronet(fl4->daddr)) { - return ERR_PTR(-EINVAL); -+ } - - if (dev_out->flags & IFF_LOOPBACK) - flags |= RTCF_LOCAL; diff --git a/lede/target/linux/qualcommax/patches-6.6/0600-1-qca-nss-ecm-support-CORE.patch b/lede/target/linux/qualcommax/patches-6.6/0600-1-qca-nss-ecm-support-CORE.patch index c9d62ecb37..c02a930f88 100644 --- a/lede/target/linux/qualcommax/patches-6.6/0600-1-qca-nss-ecm-support-CORE.patch +++ b/lede/target/linux/qualcommax/patches-6.6/0600-1-qca-nss-ecm-support-CORE.patch @@ -8,9 +8,9 @@ + struct rtnl_link_stats64 *nlstats); */ +extern bool br_is_hairpin_enabled(struct net_device *dev); - #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) - int br_multicast_list_adjacent(struct net_device *dev, -@@ -213,4 +216,42 @@ static inline clock_t br_get_ageing_time + extern void br_dev_update_stats(struct net_device *dev, + struct rtnl_link_stats64 *nlstats); +@@ -216,4 +219,42 @@ static inline clock_t br_get_ageing_time } #endif @@ -55,7 +55,7 @@ #endif --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h -@@ -143,7 +143,10 @@ extern struct net_device *__vlan_find_de +@@ -138,7 +138,10 @@ extern struct net_device *__vlan_find_de extern int vlan_for_each(struct net_device *dev, int (*action)(struct net_device *dev, int vid, void *arg), void *arg); @@ -76,12 +76,12 @@ + +} /* QCA NSS ECM support */ + - static inline struct net_device * - __vlan_find_dev_deep_rcu(struct net_device *real_dev, - __be16 vlan_proto, u16 vlan_id) + static inline bool is_vlan_dev(const struct net_device *dev) + { + return false; --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -2933,6 +2933,10 @@ enum netdev_cmd { +@@ -2907,6 +2907,10 @@ enum netdev_cmd { NETDEV_OFFLOAD_XSTATS_REPORT_USED, NETDEV_OFFLOAD_XSTATS_REPORT_DELTA, NETDEV_XDP_FEAT_CHANGE, @@ -94,7 +94,7 @@ --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h -@@ -207,6 +207,11 @@ void rt6_multipath_rebalance(struct fib6 +@@ -215,6 +215,11 @@ void rt6_multipath_rebalance(struct fib6 void rt6_uncached_list_add(struct rt6_info *rt); void rt6_uncached_list_del(struct rt6_info *rt); @@ -108,7 +108,7 @@ const struct dst_entry *dst = skb_dst(skb); --- a/include/net/neighbour.h +++ b/include/net/neighbour.h -@@ -249,6 +249,13 @@ static inline int neigh_parms_family(str +@@ -250,6 +250,13 @@ static inline int neigh_parms_family(str return p->tbl->family; } @@ -122,7 +122,7 @@ #define NEIGH_PRIV_ALIGN sizeof(long long) #define NEIGH_ENTRY_SIZE(size) ALIGN((size), NEIGH_PRIV_ALIGN) -@@ -395,6 +402,11 @@ void __neigh_for_each_release(struct nei +@@ -396,6 +403,11 @@ void __neigh_for_each_release(struct nei int (*cb)(struct neighbour *)); int neigh_xmit(int fam, struct net_device *, const void *, struct sk_buff *); @@ -134,7 +134,7 @@ struct neigh_seq_state { struct seq_net_private p; struct neigh_table *tbl; -@@ -600,4 +612,5 @@ static inline void neigh_update_is_route +@@ -601,4 +613,5 @@ static inline void neigh_update_is_route *notify = 1; } } @@ -142,7 +142,7 @@ #endif --- a/include/net/route.h +++ b/include/net/route.h -@@ -237,6 +237,11 @@ struct rtable *rt_dst_alloc(struct net_d +@@ -246,6 +246,11 @@ struct rtable *rt_dst_alloc(struct net_d unsigned int flags, u16 type, bool noxfrm); struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt); @@ -156,7 +156,7 @@ void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *); --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h -@@ -2267,4 +2267,6 @@ void br_do_suppress_nd(struct sk_buff *s +@@ -2304,4 +2304,6 @@ void br_do_suppress_nd(struct sk_buff *s u16 vid, struct net_bridge_port *p, struct nd_msg *msg); struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *m); bool br_is_neigh_suppress_enabled(const struct net_bridge_port *p, u16 vid); @@ -232,8 +232,8 @@ + int __init br_fdb_init(void) { - br_fdb_cache = kmem_cache_create("bridge_fdb_cache", -@@ -195,6 +209,25 @@ static void fdb_notify(struct net_bridge + br_fdb_cache = KMEM_CACHE(net_bridge_fdb_entry, SLAB_HWCACHE_ALIGN); +@@ -192,6 +206,25 @@ static void fdb_notify(struct net_bridge if (swdev_notify) br_switchdev_fdb_notify(br, fdb, type); @@ -259,7 +259,7 @@ skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; -@@ -519,6 +552,22 @@ out: +@@ -537,6 +570,22 @@ out: spin_unlock_bh(&br->hash_lock); } @@ -282,7 +282,7 @@ void br_fdb_cleanup(struct work_struct *work) { struct net_bridge *br = container_of(work, struct net_bridge, -@@ -527,6 +576,7 @@ void br_fdb_cleanup(struct work_struct * +@@ -545,6 +594,7 @@ void br_fdb_cleanup(struct work_struct * unsigned long delay = hold_time(br); unsigned long work_delay = delay; unsigned long now = jiffies; @@ -290,7 +290,7 @@ /* this part is tricky, in order to avoid blocking learning and * consequently forwarding, we rely on rcu to delete objects with -@@ -553,8 +603,15 @@ void br_fdb_cleanup(struct work_struct * +@@ -571,8 +621,15 @@ void br_fdb_cleanup(struct work_struct * work_delay = min(work_delay, this_timer - now); } else { spin_lock_bh(&br->hash_lock); @@ -307,7 +307,7 @@ spin_unlock_bh(&br->hash_lock); } } -@@ -891,6 +948,12 @@ void br_fdb_update(struct net_bridge *br +@@ -928,6 +985,12 @@ void br_fdb_update(struct net_bridge *br */ if (unlikely(test_bit(BR_FDB_LOCKED, &fdb->flags))) clear_bit(BR_FDB_LOCKED, &fdb->flags); @@ -319,8 +319,8 @@ + /* QCA NSS ECM support - End */ } - if (unlikely(test_bit(BR_FDB_ADDED_BY_USER, &flags))) -@@ -914,6 +977,64 @@ void br_fdb_update(struct net_bridge *br + if (unlikely(test_bit(BR_FDB_ADDED_BY_USER, &flags))) { +@@ -955,6 +1018,64 @@ void br_fdb_update(struct net_bridge *br } } @@ -418,7 +418,7 @@ /* Since more than one interface can be attached to a bridge, * there still maybe an alternate path for netconsole to use; * therefore there is no reason for a NETDEV_RELEASE event. -@@ -775,3 +785,97 @@ bool br_port_flag_is_set(const struct ne +@@ -797,3 +807,97 @@ bool br_port_flag_is_set(const struct ne return p->flags & flag; } EXPORT_SYMBOL_GPL(br_port_flag_is_set); @@ -488,7 +488,7 @@ +{ + struct pcpu_sw_netstats *tstats; + -+ // Is this a bridge? ++ // Is this a bridge? + if (!(dev->priv_flags & IFF_EBRIDGE)) + return; + @@ -518,7 +518,7 @@ +/* QCA NSS ECM support - End */ --- a/net/core/neighbour.c +++ b/net/core/neighbour.c -@@ -1275,6 +1275,22 @@ static void neigh_update_hhs(struct neig +@@ -1282,6 +1282,22 @@ static void neigh_update_hhs(struct neig } } @@ -541,7 +541,7 @@ /* Generic update routine. -- lladdr is new lladdr or NULL, if it is not supplied. -- new is new state. -@@ -1303,6 +1319,7 @@ static int __neigh_update(struct neighbo +@@ -1310,6 +1326,7 @@ static int __neigh_update(struct neighbo struct net_device *dev; int err, notify = 0; u8 old; @@ -549,7 +549,7 @@ trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid); -@@ -1317,7 +1334,10 @@ static int __neigh_update(struct neighbo +@@ -1324,7 +1341,10 @@ static int __neigh_update(struct neighbo new = old; goto out; } @@ -561,7 +561,7 @@ (old & (NUD_NOARP | NUD_PERMANENT))) goto out; -@@ -1354,7 +1374,12 @@ static int __neigh_update(struct neighbo +@@ -1361,7 +1381,12 @@ static int __neigh_update(struct neighbo - compare new & old - if they are different, check override flag */ @@ -575,7 +575,7 @@ !memcmp(lladdr, neigh->ha, dev->addr_len)) lladdr = neigh->ha; } else { -@@ -1476,8 +1501,11 @@ out: +@@ -1483,8 +1508,11 @@ out: neigh_update_gc_list(neigh); if (managed_update) neigh_update_managed_list(neigh); @@ -590,7 +590,7 @@ } --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c -@@ -1211,6 +1211,9 @@ static bool fib_valid_key_len(u32 key, u +@@ -1196,6 +1196,9 @@ static int fib_insert_alias(struct trie static void fib_remove_alias(struct trie *t, struct key_vector *tp, struct key_vector *l, struct fib_alias *old); @@ -600,7 +600,7 @@ /* Caller must hold RTNL. */ int fib_table_insert(struct net *net, struct fib_table *tb, struct fib_config *cfg, struct netlink_ext_ack *extack) -@@ -1404,6 +1407,9 @@ int fib_table_insert(struct net *net, st +@@ -1386,6 +1389,9 @@ int fib_table_insert(struct net *net, st rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, new_fa->tb_id, &cfg->fc_nlinfo, nlflags); succeeded: @@ -610,7 +610,7 @@ return 0; out_remove_new_fa: -@@ -1775,6 +1781,9 @@ int fib_table_delete(struct net *net, st +@@ -1754,6 +1760,9 @@ int fib_table_delete(struct net *net, st if (fa_to_delete->fa_state & FA_S_ACCESSED) rt_cache_flush(cfg->fc_nlinfo.nl_net); @@ -620,7 +620,7 @@ fib_release_info(fa_to_delete->fa_info); alias_free_mem_rcu(fa_to_delete); return 0; -@@ -2407,6 +2416,20 @@ void __init fib_trie_init(void) +@@ -2386,6 +2395,20 @@ void __init fib_trie_init(void) 0, SLAB_PANIC | SLAB_ACCOUNT, NULL); } @@ -643,7 +643,7 @@ struct fib_table *tb; --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c -@@ -666,6 +666,7 @@ void ndisc_send_ns(struct net_device *de +@@ -670,6 +670,7 @@ void ndisc_send_ns(struct net_device *de if (skb) ndisc_send_skb(skb, daddr, saddr); } @@ -653,7 +653,7 @@ const struct in6_addr *daddr) --- a/net/ipv6/route.c +++ b/net/ipv6/route.c -@@ -198,6 +198,9 @@ static void rt6_uncached_list_flush_dev( +@@ -196,6 +196,9 @@ static void rt6_uncached_list_flush_dev( } } @@ -663,7 +663,7 @@ static inline const void *choose_neigh_daddr(const struct in6_addr *p, struct sk_buff *skb, const void *daddr) -@@ -3868,6 +3871,10 @@ int ip6_route_add(struct fib6_config *cf +@@ -3917,6 +3920,10 @@ int ip6_route_add(struct fib6_config *cf return PTR_ERR(rt); err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack); @@ -674,7 +674,7 @@ fib6_info_release(rt); return err; -@@ -3889,6 +3896,9 @@ static int __ip6_del_rt(struct fib6_info +@@ -3938,6 +3945,9 @@ static int __ip6_del_rt(struct fib6_info err = fib6_del(rt, info); spin_unlock_bh(&table->tb6_lock); @@ -684,7 +684,7 @@ out: fib6_info_release(rt); return err; -@@ -6336,6 +6346,20 @@ static int ip6_route_dev_notify(struct n +@@ -6409,6 +6419,20 @@ static int ip6_route_dev_notify(struct n return NOTIFY_OK; } @@ -707,7 +707,7 @@ */ --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -1699,6 +1699,7 @@ const char *netdev_cmd_to_name(enum netd +@@ -1768,6 +1768,7 @@ const char *netdev_cmd_to_name(enum netd N(PRE_CHANGEADDR) N(OFFLOAD_XSTATS_ENABLE) N(OFFLOAD_XSTATS_DISABLE) N(OFFLOAD_XSTATS_REPORT_USED) N(OFFLOAD_XSTATS_REPORT_DELTA) N(XDP_FEAT_CHANGE) @@ -717,7 +717,7 @@ return "UNKNOWN_NETDEV_EVENT"; --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c -@@ -1002,6 +1002,7 @@ void inet6_ifa_finish_destroy(struct ine +@@ -993,6 +993,7 @@ void inet6_ifa_finish_destroy(struct ine kfree_rcu(ifp, rcu); } @@ -727,7 +727,7 @@ ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) --- a/include/net/vxlan.h +++ b/include/net/vxlan.h -@@ -440,6 +440,15 @@ static inline __be32 vxlan_compute_rco(u +@@ -441,6 +441,15 @@ static inline __be32 vxlan_compute_rco(u return vni_field; } @@ -754,7 +754,7 @@ IPPROTO_ENCAP = 98, /* Encapsulation Header */ #define IPPROTO_ENCAP IPPROTO_ENCAP IPPROTO_PIM = 103, /* Protocol Independent Multicast */ -@@ -327,7 +329,7 @@ struct sockaddr_in { +@@ -329,7 +331,7 @@ struct sockaddr_in { #endif /* contains the htonl type stuff.. */ @@ -774,7 +774,7 @@ IPPROTO_ENCAP = 98, /* Encapsulation Header */ #define IPPROTO_ENCAP IPPROTO_ENCAP IPPROTO_PIM = 103, /* Protocol Independent Multicast */ -@@ -327,7 +329,7 @@ struct sockaddr_in { +@@ -329,7 +331,7 @@ struct sockaddr_in { #endif /* contains the htonl type stuff.. */ @@ -785,7 +785,7 @@ #endif /* _UAPI_LINUX_IN_H */ --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c -@@ -365,7 +365,7 @@ void nf_conntrack_register_notifier(stru +@@ -365,7 +365,7 @@ int nf_conntrack_register_notifier(struc mutex_lock(&nf_ct_ecache_mutex); notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb, lockdep_is_held(&nf_ct_ecache_mutex)); diff --git a/lede/target/linux/qualcommax/patches-6.6/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch b/lede/target/linux/qualcommax/patches-6.6/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch index e02e9090db..620588e6b6 100644 --- a/lede/target/linux/qualcommax/patches-6.6/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch +++ b/lede/target/linux/qualcommax/patches-6.6/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch @@ -1,6 +1,6 @@ --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c -@@ -116,6 +116,40 @@ static void ad_marker_response_received( +@@ -115,6 +115,40 @@ static void ad_marker_response_received( struct port *port); static void ad_update_actor_keys(struct port *port, bool reset); @@ -41,7 +41,7 @@ /* ================= api to bonding and kernel code ================== */ -@@ -1073,7 +1107,31 @@ static void ad_mux_machine(struct port * +@@ -1159,7 +1193,31 @@ static void ad_mux_machine(struct port * ad_disable_collecting_distributing(port, update_slave_arr); port->ntt = true; @@ -73,7 +73,7 @@ case AD_MUX_COLLECTING_DISTRIBUTING: port->actor_oper_port_state |= LACP_STATE_COLLECTING; port->actor_oper_port_state |= LACP_STATE_DISTRIBUTING; -@@ -1917,6 +1975,7 @@ static void ad_enable_collecting_distrib +@@ -2060,6 +2118,7 @@ static void ad_enable_collecting_distrib bool *update_slave_arr) { if (port->aggregator->is_active) { @@ -81,7 +81,7 @@ slave_dbg(port->slave->bond->dev, port->slave->dev, "Enabling port %d (LAG %d)\n", port->actor_port_number, -@@ -1924,6 +1983,16 @@ static void ad_enable_collecting_distrib +@@ -2067,6 +2126,16 @@ static void ad_enable_collecting_distrib __enable_port(port); /* Slave array needs update */ *update_slave_arr = true; @@ -98,7 +98,7 @@ } } -@@ -2683,6 +2752,104 @@ int bond_3ad_get_active_agg_info(struct +@@ -2824,6 +2893,104 @@ int bond_3ad_get_active_agg_info(struct return ret; } @@ -227,7 +227,7 @@ /** * bond_dev_queue_xmit - Prepare skb for xmit. * -@@ -1189,6 +1204,23 @@ void bond_change_active_slave(struct bon +@@ -1308,6 +1323,23 @@ void bond_change_active_slave(struct bon if (BOND_MODE(bond) == BOND_MODE_8023AD) bond_3ad_handle_link_change(new_active, BOND_LINK_UP); @@ -251,7 +251,7 @@ if (bond_is_lb(bond)) bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); } else { -@@ -1833,6 +1865,7 @@ int bond_enslave(struct net_device *bond +@@ -1952,6 +1984,7 @@ int bond_enslave(struct net_device *bond const struct net_device_ops *slave_ops = slave_dev->netdev_ops; struct slave *new_slave = NULL, *prev_slave; struct sockaddr_storage ss; @@ -259,7 +259,7 @@ int link_reporting; int res = 0, i; -@@ -2278,6 +2311,15 @@ int bond_enslave(struct net_device *bond +@@ -2412,6 +2445,15 @@ skip_mac_set: bond_is_active_slave(new_slave) ? "an active" : "a backup", new_slave->link != BOND_LINK_DOWN ? "an up" : "a down"); @@ -275,7 +275,7 @@ /* enslave is successful */ bond_queue_slave_event(new_slave); return 0; -@@ -2343,6 +2385,15 @@ err_undo_flags: +@@ -2477,6 +2519,15 @@ err_undo_flags: } } @@ -291,7 +291,7 @@ return res; } -@@ -2364,6 +2415,7 @@ static int __bond_release_one(struct net +@@ -2498,6 +2549,7 @@ static int __bond_release_one(struct net struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *oldcurrent; struct sockaddr_storage ss; @@ -299,7 +299,7 @@ int old_flags = bond_dev->flags; netdev_features_t old_features = bond_dev->features; -@@ -2386,6 +2438,15 @@ static int __bond_release_one(struct net +@@ -2520,6 +2572,15 @@ static int __bond_release_one(struct net bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW); @@ -315,7 +315,7 @@ bond_sysfs_slave_del(slave); /* recompute stats just before removing the slave */ -@@ -2708,6 +2769,8 @@ static void bond_miimon_commit(struct bo +@@ -2850,6 +2911,8 @@ static void bond_miimon_commit(struct bo struct slave *slave, *primary, *active; bool do_failover = false; struct list_head *iter; @@ -324,7 +324,7 @@ ASSERT_RTNL(); -@@ -2747,6 +2810,12 @@ static void bond_miimon_commit(struct bo +@@ -2889,6 +2952,12 @@ static void bond_miimon_commit(struct bo bond_set_active_slave(slave); } @@ -337,7 +337,7 @@ slave_info(bond->dev, slave->dev, "link status definitely up, %u Mbps %s duplex\n", slave->speed == SPEED_UNKNOWN ? 0 : slave->speed, slave->duplex ? "full" : "half"); -@@ -2795,6 +2864,16 @@ static void bond_miimon_commit(struct bo +@@ -2937,6 +3006,16 @@ static void bond_miimon_commit(struct bo unblock_netpoll_tx(); } @@ -354,7 +354,7 @@ bond_set_carrier(bond); } -@@ -4047,8 +4126,219 @@ static inline u32 bond_eth_hash(struct s +@@ -4189,8 +4268,224 @@ static inline u32 bond_eth_hash(struct s return 0; ep = (struct ethhdr *)(data + mhoff); @@ -521,6 +521,11 @@ + u8 *dst_mac, void *src, + void *dst, u16 protocol, + struct net_device *bond_dev, ++ __be16 *layer4hdr); ++struct net_device *bond_get_tx_dev(struct sk_buff *skb, uint8_t *src_mac, ++ u8 *dst_mac, void *src, ++ void *dst, u16 protocol, ++ struct net_device *bond_dev, + __be16 *layer4hdr) +{ + struct bonding *bond; @@ -575,7 +580,7 @@ static bool bond_flow_ip(struct sk_buff *skb, struct flow_keys *fk, const void *data, int hlen, __be16 l2_proto, int *nhoff, int *ip_proto, bool l34) -@@ -5177,15 +5467,18 @@ static netdev_tx_t bond_3ad_xor_xmit(str +@@ -5319,15 +5614,18 @@ static netdev_tx_t bond_3ad_xor_xmit(str struct net_device *dev) { struct bonding *bond = netdev_priv(dev); @@ -601,7 +606,7 @@ } /* in broadcast mode, we send everything to all usable interfaces. */ -@@ -5435,8 +5728,9 @@ static netdev_tx_t __bond_start_xmit(str +@@ -5577,8 +5875,9 @@ static netdev_tx_t __bond_start_xmit(str return bond_xmit_roundrobin(skb, dev); case BOND_MODE_ACTIVEBACKUP: return bond_xmit_activebackup(skb, dev); @@ -614,10 +619,10 @@ return bond_xmit_broadcast(skb, dev); --- a/include/net/bond_3ad.h +++ b/include/net/bond_3ad.h -@@ -302,8 +302,15 @@ int bond_3ad_lacpdu_recv(const struct sk - struct slave *slave); +@@ -308,6 +308,14 @@ int bond_3ad_lacpdu_recv(const struct sk int bond_3ad_set_carrier(struct bonding *bond); void bond_3ad_update_lacp_rate(struct bonding *bond); + void bond_3ad_update_lacp_active(struct bonding *bond); +/* QCA NSS ECM bonding support */ +struct net_device *bond_3ad_get_tx_dev(struct sk_buff *skb, uint8_t *src_mac, + uint8_t *dst_mac, void *src, @@ -629,8 +634,6 @@ void bond_3ad_update_ad_actor_settings(struct bonding *bond); int bond_3ad_stats_fill(struct sk_buff *skb, struct bond_3ad_stats *stats); size_t bond_3ad_stats_size(void); - #endif /* _NET_BOND_3AD_H */ -- --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -90,6 +90,8 @@ @@ -642,7 +645,7 @@ #ifdef CONFIG_NET_POLL_CONTROLLER extern atomic_t netpoll_block_tx; -@@ -653,6 +655,7 @@ struct bond_net { +@@ -676,6 +678,7 @@ struct bond_net { int bond_rcv_validate(const struct sk_buff *skb, struct bonding *bond, struct slave *slave); netdev_tx_t bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); @@ -650,7 +653,7 @@ int bond_create(struct net *net, const char *name); int bond_create_sysfs(struct bond_net *net); void bond_destroy_sysfs(struct bond_net *net); -@@ -684,6 +687,13 @@ struct bond_vlan_tag *bond_verify_device +@@ -707,6 +710,13 @@ struct bond_vlan_tag *bond_verify_device int level); int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave); void bond_slave_arr_work_rearm(struct bonding *bond, unsigned long delay); @@ -664,7 +667,7 @@ void bond_work_init_all(struct bonding *bond); #ifdef CONFIG_PROC_FS -@@ -788,4 +798,18 @@ static inline netdev_tx_t bond_tx_drop(s +@@ -811,4 +821,18 @@ static inline netdev_tx_t bond_tx_drop(s return NET_XMIT_DROP; } diff --git a/mieru/README.md b/mieru/README.md index a26d219c23..d907de199d 100644 --- a/mieru/README.md +++ b/mieru/README.md @@ -63,3 +63,5 @@ Use GitHub issue. ## License Use of this software is subject to the GPL-3 license. + +[![Star History Chart](https://api.star-history.com/svg?repos=enfein/mieru&type=Date)](https://www.star-history.com/#enfein/mieru&Date) diff --git a/mieru/README.zh_CN.md b/mieru/README.zh_CN.md index 0b20ee5868..48b3f4da3f 100644 --- a/mieru/README.zh_CN.md +++ b/mieru/README.zh_CN.md @@ -61,3 +61,5 @@ mieru 的翻墙原理与 shadowsocks / v2ray 等软件类似,在客户端和 ## 许可证 使用本软件需遵从 GPL-3 协议。 + +[![Star History Chart](https://api.star-history.com/svg?repos=enfein/mieru&type=Date)](https://www.star-history.com/#enfein/mieru&Date) diff --git a/nekobox-android/app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/6.json b/nekobox-android/app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/6.json new file mode 100644 index 0000000000..11b6e58a2f --- /dev/null +++ b/nekobox-android/app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/6.json @@ -0,0 +1,373 @@ +{ + "formatVersion": 1, + "database": { + "version": 6, + "identityHash": "3d3db9106a89d6f20ef3fde6e81dbaa9", + "entities": [ + { + "tableName": "proxy_groups", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL, `landingProxy` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userOrder", + "columnName": "userOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ungrouped", + "columnName": "ungrouped", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subscription", + "columnName": "subscription", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isSelector", + "columnName": "isSelector", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "frontProxy", + "columnName": "frontProxy", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "landingProxy", + "columnName": "landingProxy", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "proxy_entities", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `mieruBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `shadowTLSBean` BLOB, `anyTLSBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "groupId", + "columnName": "groupId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userOrder", + "columnName": "userOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tx", + "columnName": "tx", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "rx", + "columnName": "rx", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ping", + "columnName": "ping", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "error", + "columnName": "error", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "socksBean", + "columnName": "socksBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "httpBean", + "columnName": "httpBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "ssBean", + "columnName": "ssBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "vmessBean", + "columnName": "vmessBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "trojanBean", + "columnName": "trojanBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "trojanGoBean", + "columnName": "trojanGoBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "mieruBean", + "columnName": "mieruBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "naiveBean", + "columnName": "naiveBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "hysteriaBean", + "columnName": "hysteriaBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "tuicBean", + "columnName": "tuicBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "sshBean", + "columnName": "sshBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "wgBean", + "columnName": "wgBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "shadowTLSBean", + "columnName": "shadowTLSBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "anyTLSBean", + "columnName": "anyTLSBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "chainBean", + "columnName": "chainBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "nekoBean", + "columnName": "nekoBean", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "configBean", + "columnName": "configBean", + "affinity": "BLOB", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "groupId", + "unique": false, + "columnNames": [ + "groupId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "rules", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `config` TEXT NOT NULL DEFAULT '', `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `packages` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "config", + "columnName": "config", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "userOrder", + "columnName": "userOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "domains", + "columnName": "domains", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ip", + "columnName": "ip", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "port", + "columnName": "port", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sourcePort", + "columnName": "sourcePort", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "network", + "columnName": "network", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "source", + "columnName": "source", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "protocol", + "columnName": "protocol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "outbound", + "columnName": "outbound", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "packages", + "columnName": "packages", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3d3db9106a89d6f20ef3fde6e81dbaa9')" + ] + } +} \ No newline at end of file diff --git a/nekobox-android/app/src/main/assets/analysis.txt b/nekobox-android/app/src/main/assets/analysis.txt deleted file mode 100644 index e16715db89..0000000000 --- a/nekobox-android/app/src/main/assets/analysis.txt +++ /dev/null @@ -1,3 +0,0 @@ -domain:appcenter.ms -domain:firebase.io -domain:crashlytics.com diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/Constants.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/Constants.kt index d44a3b601c..caf363f6fd 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/Constants.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/Constants.kt @@ -16,6 +16,8 @@ object Key { const val MODE_VPN = "vpn" const val MODE_PROXY = "proxy" + const val GLOBAL_CUSTOM_CONFIG = "globalCustomConfig" + const val REMOTE_DNS = "remoteDns" const val DIRECT_DNS = "directDns" const val ENABLE_DNS_ROUTING = "enableDnsRouting" diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/SagerNet.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/SagerNet.kt index 02886a6d70..f38305d467 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/SagerNet.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/SagerNet.kt @@ -29,6 +29,7 @@ import kotlinx.coroutines.DEBUG_PROPERTY_NAME import kotlinx.coroutines.DEBUG_PROPERTY_VALUE_ON import libcore.Libcore import moe.matsuri.nb4a.NativeInterface +import moe.matsuri.nb4a.net.LocalResolverImpl import moe.matsuri.nb4a.utils.JavaUtil import moe.matsuri.nb4a.utils.cleanWebview import java.io.File @@ -53,10 +54,21 @@ class SagerNet : Application(), override fun onCreate() { super.onCreate() - System.setProperty(DEBUG_PROPERTY_NAME, DEBUG_PROPERTY_VALUE_ON) Thread.setDefaultUncaughtExceptionHandler(CrashHandler) if (isMainProcess || isBgProcess) { + externalAssets.mkdirs() + Seq.setContext(this) + Libcore.initCore( + process, + cacheDir.absolutePath + "/", + filesDir.absolutePath + "/", + externalAssets.absolutePath + "/", + DataStore.logBufSize, + DataStore.logLevel > 0, + nativeInterface, nativeInterface, LocalResolverImpl + ) + // fix multi process issue in Android 9+ JavaUtil.handleWebviewDir(this) @@ -66,21 +78,6 @@ class SagerNet : Application(), } } - Seq.setContext(this) - updateNotificationChannels() - - // nb4a: init core - externalAssets.mkdirs() - Libcore.initCore( - process, - cacheDir.absolutePath + "/", - filesDir.absolutePath + "/", - externalAssets.absolutePath + "/", - DataStore.logBufSize, - DataStore.logLevel > 0, - nativeInterface, nativeInterface - ) - if (isMainProcess) { Theme.apply(this) Theme.applyNightTheme() @@ -88,17 +85,22 @@ class SagerNet : Application(), DefaultNetworkListener.start(this) { underlyingNetwork = it } + + updateNotificationChannels() } } - if (BuildConfig.DEBUG) StrictMode.setVmPolicy( - StrictMode.VmPolicy.Builder() - .detectLeakedSqlLiteObjects() - .detectLeakedClosableObjects() - .detectLeakedRegistrationObjects() - .penaltyLog() - .build() - ) + if (BuildConfig.DEBUG) { + System.setProperty(DEBUG_PROPERTY_NAME, DEBUG_PROPERTY_VALUE_ON) + StrictMode.setVmPolicy( + StrictMode.VmPolicy.Builder() + .detectLeakedSqlLiteObjects() + .detectLeakedClosableObjects() + .detectLeakedRegistrationObjects() + .penaltyLog() + .build() + ) + } } override fun onConfigurationChanged(newConfig: Configuration) { @@ -178,6 +180,10 @@ class SagerNet : Application(), "service-subscription", application.getText(R.string.service_subscription), NotificationManager.IMPORTANCE_DEFAULT + ), NotificationChannel( + "connection-test", + application.getText(R.string.connection_test), + NotificationManager.IMPORTANCE_DEFAULT ) ) ) @@ -196,7 +202,7 @@ class SagerNet : Application(), var underlyingNetwork: Network? = null - var appVersionNameForDisplay = lazy { + var appVersionNameForDisplay = { var n = BuildConfig.VERSION_NAME if (isPreview) { n += " " + BuildConfig.PRE_VERSION_NAME @@ -207,7 +213,7 @@ class SagerNet : Application(), n += " DEBUG" } n - } + }() } } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt index 4d69504366..e760983dcd 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt @@ -105,6 +105,10 @@ class BaseService { override fun getProfileName(): String = data?.proxy?.displayProfileName ?: "Idle" override fun registerCallback(cb: ISagerNetServiceCallback, id: Int) { + if (id == SagerConnection.CONNECTION_ID_RESTART_BG) { + Runtime.getRuntime().exit(0) + return + } if (!callbackIdMap.contains(cb)) { callbacks.register(cb) } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt index f944058dc5..5b860b35f2 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt @@ -3,24 +3,21 @@ package io.nekohasekai.sagernet.bg import android.system.ErrnoException import android.system.Os import android.system.OsConstants -import android.text.TextUtils import io.nekohasekai.sagernet.ktx.Logs import java.io.File import java.io.IOException +import androidx.core.text.isDigitsOnly object Executable { private val EXECUTABLES = setOf( - "libtrojan.so", - "libtrojan-go.so", - "libnaive.so", - "libtuic.so", - "libhysteria.so" + "libtrojan.so", "libtrojan-go.so", "libnaive.so", "libtuic.so", "libhysteria.so" ) fun killAll(alsoKillBg: Boolean = false) { - for (process in File("/proc").listFiles { _, name -> TextUtils.isDigitsOnly(name) } - ?: return) { - val exe = File(try { + // kill bg may fail + for (process in File("/proc").listFiles { _, name -> name.isDigitsOnly() } ?: return) { + val exe = File( + try { File(process, "cmdline").inputStream().bufferedReader().use { it.readText() } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/SagerConnection.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/SagerConnection.kt index ab7d5a493d..97ff4b8a07 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/SagerConnection.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/SagerConnection.kt @@ -32,6 +32,9 @@ class SagerConnection( const val CONNECTION_ID_TILE = 1 const val CONNECTION_ID_MAIN_ACTIVITY_FOREGROUND = 2 const val CONNECTION_ID_MAIN_ACTIVITY_BACKGROUND = 3 + const val CONNECTION_ID_RESTART_BG = 4 + + var restartingApp = false } interface Callback { @@ -124,7 +127,7 @@ class SagerConnection( } catch (e: RemoteException) { e.printStackTrace() } - callback!!.onServiceConnected(service) + callback?.onServiceConnected(service) } override fun onServiceDisconnected(name: ComponentName?) { @@ -137,7 +140,9 @@ class SagerConnection( override fun binderDied() { service = null callbackRegistered = false - callback?.also { runOnMainDispatcher { it.onBinderDied() } } + if (!restartingApp) { + callback?.also { runOnMainDispatcher { it.onBinderDied() } } + } } private fun unregisterCallback() { @@ -149,7 +154,7 @@ class SagerConnection( callbackRegistered = false } - fun connect(context: Context, callback: Callback) { + fun connect(context: Context, callback: Callback?) { if (connectionActive) return connectionActive = true check(this.callback == null) diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/BoxInstance.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/BoxInstance.kt index 84586bc2c3..9f16723de1 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/BoxInstance.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/BoxInstance.kt @@ -21,6 +21,7 @@ import io.nekohasekai.sagernet.plugin.PluginManager import kotlinx.coroutines.* import libcore.BoxInstance import libcore.Libcore +import moe.matsuri.nb4a.net.LocalResolverImpl import java.io.File abstract class BoxInstance( @@ -48,7 +49,7 @@ abstract class BoxInstance( } protected open suspend fun loadConfig() { - box = Libcore.newSingBoxInstance(config.config) + box = Libcore.newSingBoxInstance(config.config, LocalResolverImpl) } open suspend fun init() { diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/ProxyInstance.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/ProxyInstance.kt index 293c657424..9758a5c40d 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/ProxyInstance.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/ProxyInstance.kt @@ -7,8 +7,6 @@ import io.nekohasekai.sagernet.database.ProxyEntity import io.nekohasekai.sagernet.ktx.Logs import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher import kotlinx.coroutines.runBlocking -import libcore.Libcore -import moe.matsuri.nb4a.net.LocalResolverImpl import moe.matsuri.nb4a.utils.JavaUtil class ProxyInstance(profile: ProxyEntity, var service: BaseService.Interface? = null) : @@ -45,7 +43,6 @@ class ProxyInstance(profile: ProxyEntity, var service: BaseService.Interface? = } override suspend fun loadConfig() { - Libcore.registerLocalDNSTransport(LocalResolverImpl) super.loadConfig() } @@ -59,7 +56,6 @@ class ProxyInstance(profile: ProxyEntity, var service: BaseService.Interface? = } override fun close() { - Libcore.registerLocalDNSTransport(null) super.close() runBlocking { looper?.stop() diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/TestInstance.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/TestInstance.kt index 57d1a17026..bc6907137c 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/TestInstance.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/bg/proto/TestInstance.kt @@ -10,6 +10,7 @@ import io.nekohasekai.sagernet.ktx.tryResume import io.nekohasekai.sagernet.ktx.tryResumeWithException import kotlinx.coroutines.delay import libcore.Libcore +import moe.matsuri.nb4a.net.LocalResolverImpl import kotlin.coroutines.suspendCoroutine class TestInstance(profile: ProxyEntity, val link: String, private val timeout: Int) : @@ -46,7 +47,7 @@ class TestInstance(profile: ProxyEntity, val link: String, private val timeout: override suspend fun loadConfig() { // don't call destroyAllJsi here if (BuildConfig.DEBUG) Logs.d(config.config) - box = Libcore.newSingBoxInstance(config.config) + box = Libcore.newSingBoxInstance(config.config, LocalResolverImpl) } } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt index df6f06ab4a..06bb501338 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt @@ -17,7 +17,6 @@ import io.nekohasekai.sagernet.ktx.int import io.nekohasekai.sagernet.ktx.long import io.nekohasekai.sagernet.ktx.parsePort import io.nekohasekai.sagernet.ktx.string -import io.nekohasekai.sagernet.ktx.stringSet import io.nekohasekai.sagernet.ktx.stringToInt import io.nekohasekai.sagernet.ktx.stringToIntIfExists import moe.matsuri.nb4a.TempDatabase @@ -41,6 +40,10 @@ object DataStore : OnPreferenceDataStoreChangeListener { var vpnService: VpnService? = null var baseService: BaseService.Interface? = null + // main + + var runningTest = false + fun currentGroupId(): Long { val currentSelected = configurationStore.getLong(Key.PROFILE_GROUP, -1) if (currentSelected > 0L) return currentSelected @@ -108,10 +111,12 @@ object DataStore : OnPreferenceDataStoreChangeListener { var speedInterval by configurationStore.stringToInt(Key.SPEED_INTERVAL) var showGroupInNotification by configurationStore.boolean("showGroupInNotification") + var globalCustomConfig by configurationStore.string(Key.GLOBAL_CUSTOM_CONFIG) { "" } + var remoteDns by configurationStore.string(Key.REMOTE_DNS) { "https://dns.google/dns-query" } var directDns by configurationStore.string(Key.DIRECT_DNS) { "https://223.5.5.5/dns-query" } var enableDnsRouting by configurationStore.boolean(Key.ENABLE_DNS_ROUTING) { true } - var enableFakeDns by configurationStore.boolean(Key.ENABLE_FAKEDNS) + var enableFakeDns by configurationStore.boolean(Key.ENABLE_FAKEDNS) { true } var rulesProvider by configurationStore.stringToInt(Key.RULES_PROVIDER) var logLevel by configurationStore.stringToInt(Key.LOG_LEVEL) @@ -154,7 +159,7 @@ object DataStore : OnPreferenceDataStoreChangeListener { var connectionTestConcurrent by configurationStore.int("connectionTestConcurrent") { 5 } var alwaysShowAddress by configurationStore.boolean(Key.ALWAYS_SHOW_ADDRESS) - var tunImplementation by configurationStore.stringToInt(Key.TUN_IMPLEMENTATION) { TunImplementation.MIXED } + var tunImplementation by configurationStore.stringToInt(Key.TUN_IMPLEMENTATION) { TunImplementation.GVISOR } var profileTrafficStatistics by configurationStore.boolean(Key.PROFILE_TRAFFIC_STATISTICS) { true } var yacdURL by configurationStore.string("yacdURL") { "http://127.0.0.1:9090/ui" } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/ProfileManager.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/ProfileManager.kt index 8049cf89ad..ba21dde44d 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/ProfileManager.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/ProfileManager.kt @@ -200,18 +200,6 @@ object ProfileManager { outbound = -2 ) ) - createRule( - RuleEntity( - name = app.getString(R.string.route_opt_block_analysis), - domains = app.assets.open("analysis.txt").use { - it.bufferedReader() - .readLines() - .filter { it.isNotBlank() } - .joinToString("\n") - }, - outbound = -2, - ) - ) val fuckedCountry = mutableListOf("cn:中国") if (Locale.getDefault().country != Locale.CHINA.country) { // 非中文用户 diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/RuleEntity.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/RuleEntity.kt index 7fb409dc4f..7d610c5e40 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/RuleEntity.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/RuleEntity.kt @@ -12,6 +12,8 @@ import kotlinx.parcelize.Parcelize data class RuleEntity( @PrimaryKey(autoGenerate = true) var id: Long = 0L, var name: String = "", + @ColumnInfo(defaultValue = "") + var config: String = "", var userOrder: Long = 0L, var enabled: Boolean = false, var domains: String = "", @@ -31,11 +33,12 @@ data class RuleEntity( fun mkSummary(): String { var summary = "" + if (config.isNotBlank()) summary += "[config]\n" if (domains.isNotBlank()) summary += "$domains\n" if (ip.isNotBlank()) summary += "$ip\n" - if (source.isNotBlank()) summary += "source: $source\n" - if (sourcePort.isNotBlank()) summary += "sourcePort: $sourcePort\n" - if (port.isNotBlank()) summary += "port: $port\n" + if (source.isNotBlank()) summary += "src ip: $source\n" + if (sourcePort.isNotBlank()) summary += "src port: $sourcePort\n" + if (port.isNotBlank()) summary += "dst port: $port\n" if (network.isNotBlank()) summary += "network: $network\n" if (protocol.isNotBlank()) summary += "protocol: $protocol\n" if (packages.isNotEmpty()) summary += app.getString( diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt index cb9cade6be..ececc106eb 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt @@ -16,10 +16,11 @@ import kotlinx.coroutines.launch @Database( entities = [ProxyGroup::class, ProxyEntity::class, RuleEntity::class], - version = 5, + version = 6, autoMigrations = [ AutoMigration(from = 3, to = 4), - AutoMigration(from = 4, to = 5) + AutoMigration(from = 4, to = 5), + AutoMigration(from = 5, to = 6) ] ) @TypeConverters(value = [KryoConverters::class, GsonConverters::class]) @@ -33,6 +34,7 @@ abstract class SagerDatabase : RoomDatabase() { SagerNet.application.getDatabasePath(Key.DB_PROFILE).parentFile?.mkdirs() Room.databaseBuilder(SagerNet.application, SagerDatabase::class.java, Key.DB_PROFILE) // .addMigrations(*SagerDatabase_Migrations.build()) + .setJournalMode(JournalMode.TRUNCATE) .allowMainThreadQueries() .enableMultiInstanceInvalidation() .fallbackToDestructiveMigration() diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/preference/PublicDatabase.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/preference/PublicDatabase.kt index e9296de556..d4ebf98004 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/preference/PublicDatabase.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/database/preference/PublicDatabase.kt @@ -16,6 +16,7 @@ abstract class PublicDatabase : RoomDatabase() { val instance by lazy { SagerNet.application.getDatabasePath(Key.DB_PROFILE).parentFile?.mkdirs() Room.databaseBuilder(SagerNet.application, PublicDatabase::class.java, Key.DB_PUBLIC) + .setJournalMode(JournalMode.TRUNCATE) .allowMainThreadQueries() .enableMultiInstanceInvalidation() .fallbackToDestructiveMigration() diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt index e7cda94215..397aab0a8d 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt @@ -82,7 +82,6 @@ fun buildConfig( val globalOutbounds = HashMap() val selectorNames = ArrayList() val group = SagerDatabase.groupDao.getById(proxy.groupId) - val optionsToMerge = proxy.requireBean().customConfigJson ?: "" fun ProxyEntity.resolveChainInternal(): MutableList { val bean = requireBean() @@ -255,13 +254,13 @@ fun buildConfig( add(entity) } - var currentOutbound = mutableMapOf() - lateinit var pastOutbound: MutableMap + var currentOutbound: SingBoxOption + lateinit var pastOutbound: SingBoxOption lateinit var pastInboundTag: String var pastEntity: ProxyEntity? = null val externalChainMap = LinkedHashMap() externalIndexMap.add(IndexEntity(externalChainMap)) - val chainOutbounds = ArrayList>() + val chainOutbounds = ArrayList() // chainTagOut: v2ray outbound tag for this chain var chainTagOut = "" @@ -309,7 +308,7 @@ fun buildConfig( outbound = tagOut }) } else { - pastOutbound["detour"] = tagOut + pastOutbound._hack_config_map["detour"] = tagOut } } else { // index == 0 means last profile in chain / not chain @@ -332,53 +331,49 @@ fun buildConfig( type = "socks" server = LOCALHOST server_port = localPort - }.asMap() - } else { // internal outbound + } + } else { + // internal outbound + currentOutbound = when (bean) { - is ConfigBean -> - gson.fromJson(bean.config, currentOutbound.javaClass) + is ConfigBean -> CustomSingBoxOption(bean.config) is ShadowTLSBean -> // before StandardV2RayBean - buildSingBoxOutboundShadowTLSBean(bean).asMap() + buildSingBoxOutboundShadowTLSBean(bean) is StandardV2RayBean -> // http/trojan/vmess/vless - buildSingBoxOutboundStandardV2RayBean(bean).asMap() + buildSingBoxOutboundStandardV2RayBean(bean) is HysteriaBean -> buildSingBoxOutboundHysteriaBean(bean) is TuicBean -> - buildSingBoxOutboundTuicBean(bean).asMap() + buildSingBoxOutboundTuicBean(bean) is SOCKSBean -> - buildSingBoxOutboundSocksBean(bean).asMap() + buildSingBoxOutboundSocksBean(bean) is ShadowsocksBean -> - buildSingBoxOutboundShadowsocksBean(bean).asMap() + buildSingBoxOutboundShadowsocksBean(bean) is WireGuardBean -> - buildSingBoxOutboundWireguardBean(bean).asMap() + buildSingBoxOutboundWireguardBean(bean) is SSHBean -> - buildSingBoxOutboundSSHBean(bean).asMap() + buildSingBoxOutboundSSHBean(bean) is AnyTLSBean -> - buildSingBoxOutboundAnyTLSBean(bean).asMap() + buildSingBoxOutboundAnyTLSBean(bean) else -> throw IllegalStateException("can't reach") } - currentOutbound.apply { - // TODO nb4a keepAliveInterval? -// val keepAliveInterval = DataStore.tcpKeepAliveInterval -// val needKeepAliveInterval = keepAliveInterval !in intArrayOf(0, 15) - - if (!muxApplied) { - val muxObj = proxyEntity.singMux() - if (muxObj != null && muxObj.enabled) { - muxApplied = true - currentOutbound["multiplex"] = muxObj.asMap() - } + // internal mux + if (!muxApplied) { + val muxObj = proxyEntity.singMux() + if (muxObj != null && muxObj.enabled) { + muxApplied = true + currentOutbound._hack_config_map["multiplex"] = muxObj.asMap() } } } @@ -388,8 +383,8 @@ fun buildConfig( // udp over tcp try { val sUoT = bean.javaClass.getField("sUoT").get(bean) - if (sUoT is Boolean && sUoT == true) { - currentOutbound["udp_over_tcp"] = true + if (sUoT is Boolean && sUoT) { + _hack_config_map["udp_over_tcp"] = true } } catch (_: Exception) { } @@ -401,19 +396,13 @@ fun buildConfig( domainListDNSDirectForce.add("full:$serverAddress") } } - currentOutbound["domain_strategy"] = + _hack_config_map["domain_strategy"] = if (forTest) "" else defaultServerDomainStrategy - // custom JSON merge - if (bean.customOutboundJson.isNotBlank()) { - Util.mergeJSON( - bean.customOutboundJson, - currentOutbound as MutableMap - ) - } - } + _hack_config_map["tag"] = tagOut - currentOutbound["tag"] = tagOut + _hack_custom_config = bean.customOutboundJson + } // External proxy need a dokodemo-door inbound to forward the traffic // For external proxy software, their traffic must goes to v2ray-core to use protected fd. @@ -472,8 +461,8 @@ fun buildConfig( // build outbounds if (buildSelector) { - val list = group?.id?.let { SagerDatabase.proxyDao.getByGroup(it) } - list?.forEach { + val list = group.id.let { SagerDatabase.proxyDao.getByGroup(it) } + list.forEach { tagMap[it.id] = buildChain(it.id, it) } outbounds.add(0, Outbound_SelectorOptions().apply { @@ -481,7 +470,7 @@ fun buildConfig( tag = TAG_PROXY default_ = tagMap[proxy.id] outbounds = tagMap.values.toList() - }.asMap()) + }) } else { buildChain(0, proxy) } @@ -591,6 +580,8 @@ fun buildConfig( -2L -> TAG_BLOCK else -> if (outId == proxy.id) TAG_PROXY else tagMap[outId] ?: "" } + + _hack_custom_config = rule.config } if (!ruleObj.checkEmpty()) { @@ -620,7 +611,7 @@ fun buildConfig( for (freedom in arrayOf(TAG_DIRECT, TAG_BYPASS)) outbounds.add(Outbound().apply { tag = freedom type = "direct" - }.asMap()) + }) // Bypass Lookup for the first profile bypassDNSBeans.forEach { @@ -746,16 +737,18 @@ fun buildConfig( }) } } + + _hack_custom_config = DataStore.globalCustomConfig }.let { + val configMap = it.asMap() + Util.mergeJSON(configMap, proxy.requireBean().customConfigJson) ConfigBuildResult( - gson.toJson(it.asMap().apply { - Util.mergeJSON(optionsToMerge, this) - }), + gson.toJson(configMap), externalIndexMap, proxy.id, trafficMap, tagMap, - if (buildSelector) group!!.id else -1L + if (buildSelector) group.id else -1L ) } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt index 22dfeac525..1e78a29f51 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt @@ -272,7 +272,7 @@ fun HysteriaBean.canUseSingBox(): Boolean { return true } -fun buildSingBoxOutboundHysteriaBean(bean: HysteriaBean): MutableMap { +fun buildSingBoxOutboundHysteriaBean(bean: HysteriaBean): SingBoxOptions.SingBoxOption { return when (bean.protocolVersion) { 1 -> SingBoxOptions.Outbound_HysteriaOptions().apply { type = "hysteria" @@ -311,7 +311,7 @@ fun buildSingBoxOutboundHysteriaBean(bean: HysteriaBean): MutableMap SingBoxOptions.Outbound_Hysteria2Options().apply { type = "hysteria2" @@ -350,9 +350,9 @@ fun buildSingBoxOutboundHysteriaBean(bean: HysteriaBean): MutableMap mutableMapOf("error_version" to bean.protocolVersion) + else -> error("error_version $bean.protocolVersion") } } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt index 943674bd89..28213489a0 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt @@ -58,6 +58,7 @@ object RawUpdater : GroupUpdater() { val response = Libcore.newHttpClient().apply { trySocks5(DataStore.mixedPort) + tryH3Direct() when (DataStore.appTLSVersion) { "1.3" -> restrictedTLS() } @@ -73,6 +74,17 @@ object RawUpdater : GroupUpdater() { subscription.subscriptionUserinfo = Util.getStringBox(response.getHeader("Subscription-Userinfo")) + + // 修改默认名字 + if (proxyGroup.name?.startsWith("Subscription #") == true) { + var remoteName = Util.getStringBox(response.getHeader("content-disposition")) + if (remoteName.isNotBlank()) { + remoteName = Util.decodeFilename(remoteName) + if (remoteName.isNotBlank()) { + proxyGroup.name = remoteName + } + } + } } val proxiesMap = LinkedHashMap() diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ktx/Utils.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ktx/Utils.kt index 4023c9b3da..3e176c8ed6 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ktx/Utils.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ktx/Utils.kt @@ -20,6 +20,8 @@ import androidx.activity.result.ActivityResultLauncher import androidx.annotation.AttrRes import androidx.annotation.ColorRes import androidx.core.content.ContextCompat +import androidx.core.view.isGone +import androidx.core.view.isVisible import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager @@ -30,10 +32,10 @@ import com.jakewharton.processphoenix.ProcessPhoenix import io.nekohasekai.sagernet.BuildConfig import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.SagerNet -import io.nekohasekai.sagernet.bg.Executable +import io.nekohasekai.sagernet.aidl.ISagerNetService +import io.nekohasekai.sagernet.bg.BaseService +import io.nekohasekai.sagernet.bg.SagerConnection import io.nekohasekai.sagernet.database.DataStore -import io.nekohasekai.sagernet.database.SagerDatabase -import io.nekohasekai.sagernet.database.preference.PublicDatabase import io.nekohasekai.sagernet.ui.MainActivity import io.nekohasekai.sagernet.ui.ThemedActivity import kotlinx.coroutines.Dispatchers @@ -201,7 +203,7 @@ val shortAnimTime by lazy { fun View.crossFadeFrom(other: View) { clearAnimation() other.clearAnimation() - if (visibility == View.VISIBLE && other.visibility == View.GONE) return + if (isVisible && other.isGone) return alpha = 0F visibility = View.VISIBLE animate().alpha(1F).duration = shortAnimTime @@ -248,18 +250,35 @@ fun Fragment.needReload() { fun Fragment.needRestart() { snackbar(R.string.need_restart).setAction(R.string.apply) { - SagerNet.stopService() - val ctx = requireContext() - runOnDefaultDispatcher { - delay(500) - SagerDatabase.instance.close() - PublicDatabase.instance.close() - Executable.killAll(true) - ProcessPhoenix.triggerRebirth(ctx, Intent(ctx, MainActivity::class.java)) - } + triggerFullRestart(requireContext()) }.show() } +fun triggerFullRestart(ctx: Context) { + runOnDefaultDispatcher { + SagerNet.stopService() + delay(500) + SagerConnection.restartingApp = true + val connection = SagerConnection(SagerConnection.CONNECTION_ID_RESTART_BG) + connection.connect(ctx, RestartCallback { + ProcessPhoenix.triggerRebirth(ctx, Intent(ctx, MainActivity::class.java)) + }) + } +} + +private class RestartCallback(val callback: () -> Unit) : SagerConnection.Callback { + override fun stateChanged( + state: BaseService.State, + profileName: String?, + msg: String? + ) { + } + + override fun onServiceConnected(service: ISagerNetService) { + callback() + } +} + fun Context.getColour(@ColorRes colorRes: Int): Int { return ContextCompat.getColor(this, colorRes) } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/AboutFragment.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/AboutFragment.kt index 3609ae6752..f6afc4b3f6 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/AboutFragment.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/AboutFragment.kt @@ -80,7 +80,7 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) { MaterialAboutActionItem.Builder() .icon(R.drawable.ic_baseline_update_24) .text(R.string.app_version) - .subText(SagerNet.appVersionNameForDisplay.value) + .subText(SagerNet.appVersionNameForDisplay) .setOnClickAction { requireContext().launchCustomTab( "https://github.com/MatsuriDayo/NekoBoxForAndroid/releases" @@ -216,7 +216,6 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) { try { val client = Libcore.newHttpClient().apply { modernTLS() - keepAlive() trySocks5(DataStore.mixedPort) } val response = client.newRequest().apply { @@ -252,7 +251,7 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) { .setMessage( context.getString( R.string.update_dialog_message, - SagerNet.appVersionNameForDisplay.value, + SagerNet.appVersionNameForDisplay, releaseName ) ) @@ -267,6 +266,7 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) { } } } catch (e: Exception) { + Logs.w(e) runOnMainDispatcher { Toast.makeText(app, e.readableMessage, Toast.LENGTH_SHORT).show() } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/BackupFragment.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/BackupFragment.kt index 87aa2a0347..b439225f83 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/BackupFragment.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/BackupFragment.kt @@ -16,6 +16,7 @@ import com.jakewharton.processphoenix.ProcessPhoenix import io.nekohasekai.sagernet.BuildConfig import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.SagerNet +import io.nekohasekai.sagernet.bg.Executable import io.nekohasekai.sagernet.database.* import io.nekohasekai.sagernet.database.preference.KeyValuePair import io.nekohasekai.sagernet.database.preference.PublicDatabase @@ -23,6 +24,7 @@ import io.nekohasekai.sagernet.databinding.LayoutBackupBinding import io.nekohasekai.sagernet.databinding.LayoutImportBinding import io.nekohasekai.sagernet.databinding.LayoutProgressBinding import io.nekohasekai.sagernet.ktx.* +import kotlinx.coroutines.delay import moe.matsuri.nb4a.utils.Util import org.json.JSONArray import org.json.JSONObject @@ -34,33 +36,45 @@ class BackupFragment : NamedFragment(R.layout.layout_backup) { override fun name0() = app.getString(R.string.backup) var content = "" - private val exportSettings = registerForActivityResult(ActivityResultContracts.CreateDocument()) { data -> - if (data != null) { - runOnDefaultDispatcher { - try { - requireActivity().contentResolver.openOutputStream( - data - )!!.bufferedWriter().use { - it.write(content) - } - onMainDispatcher { - snackbar(getString(R.string.action_export_msg)).show() - } - } catch (e: Exception) { - Logs.w(e) - onMainDispatcher { - snackbar(e.readableMessage).show() + private val exportSettings = + registerForActivityResult(ActivityResultContracts.CreateDocument()) { data -> + if (data != null) { + runOnDefaultDispatcher { + try { + requireActivity().contentResolver.openOutputStream( + data + )!!.bufferedWriter().use { + it.write(content) + } + onMainDispatcher { + snackbar(getString(R.string.action_export_msg)).show() + } + } catch (e: Exception) { + Logs.w(e) + onMainDispatcher { + snackbar(e.readableMessage).show() + } } } - } } - } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val binding = LayoutBackupBinding.bind(view) + + binding.resetSettings.setOnClickListener { + MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.confirm) + .setMessage(R.string.reset_settings_message) + .setNegativeButton(R.string.no, null) + .setPositiveButton(R.string.yes) { _, _ -> + DataStore.configurationStore.reset() + triggerFullRestart(requireContext()) + } + .show() + } + binding.actionExport.setOnClickListener { runOnDefaultDispatcher { content = doBackup( @@ -230,9 +244,7 @@ class BackupFragment : NamedFragment(R.layout.layout_backup) { import.backupRules.isChecked, import.backupSettings.isChecked ) - ProcessPhoenix.triggerRebirth( - requireContext(), Intent(requireContext(), MainActivity::class.java) - ) + triggerFullRestart(requireContext()) }.onFailure { Logs.w(it) onMainDispatcher { diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt index d915244272..0540910750 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt @@ -1,8 +1,8 @@ package io.nekohasekai.sagernet.ui +import android.annotation.SuppressLint import android.content.Intent import android.graphics.Color -import android.net.Uri import android.os.Bundle import android.os.SystemClock import android.provider.OpenableColumns @@ -22,6 +22,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.Toolbar +import androidx.core.net.toUri import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.core.view.size @@ -92,12 +93,11 @@ import io.nekohasekai.sagernet.ui.profile.WireGuardSettingsActivity import io.nekohasekai.sagernet.widget.QRCodeDialog import io.nekohasekai.sagernet.widget.UndoSnackbarManager import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job -import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch -import kotlinx.coroutines.newFixedThreadPoolContext import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import moe.matsuri.nb4a.Protocols @@ -105,16 +105,15 @@ import moe.matsuri.nb4a.Protocols.getProtocolColor import moe.matsuri.nb4a.proxy.anytls.AnyTLSSettingsActivity import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity import moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSSettingsActivity +import moe.matsuri.nb4a.ui.ConnectionTestNotification import okhttp3.internal.closeQuietly -import java.net.InetAddress import java.net.InetSocketAddress import java.net.Socket import java.net.UnknownHostException -import java.util.Collections +import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.atomic.AtomicInteger import java.util.zip.ZipInputStream -import kotlin.collections.set class ConfigurationFragment @JvmOverloads constructor( val select: Boolean = false, val selectedItem: ProxyEntity? = null, val titleRes: Int = 0 @@ -160,6 +159,7 @@ class ConfigurationFragment @JvmOverloads constructor( override fun onQueryTextSubmit(query: String): Boolean = false + @SuppressLint("DetachAndAttachSameFragment") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -317,7 +317,7 @@ class ConfigurationFragment @JvmOverloads constructor( snackbar(getString(R.string.no_proxies_found_in_file)).show() } else import(proxies) } catch (e: SubscriptionFoundException) { - (requireActivity() as MainActivity).importSubscription(Uri.parse(e.link)) + (requireActivity() as MainActivity).importSubscription(e.link.toUri()) } catch (e: Exception) { Logs.w(e) onMainDispatcher { @@ -360,7 +360,7 @@ class ConfigurationFragment @JvmOverloads constructor( snackbar(getString(R.string.no_proxies_found_in_clipboard)).show() } else import(proxies) } catch (e: SubscriptionFoundException) { - (requireActivity() as MainActivity).importSubscription(Uri.parse(e.link)) + (requireActivity() as MainActivity).importSubscription(e.link.toUri()) } catch (e: Exception) { Logs.w(e) @@ -597,28 +597,41 @@ class ConfigurationFragment @JvmOverloads constructor( inner class TestDialog { val binding = LayoutProgressListBinding.inflate(layoutInflater) val builder = MaterialAlertDialogBuilder(requireContext()).setView(binding.root) - .setNegativeButton(android.R.string.cancel) { _, _ -> - cancel() + .setPositiveButton(R.string.minimize) { _, _ -> + minimize() } - .setOnDismissListener { + .setNegativeButton(android.R.string.cancel) { _, _ -> cancel() } .setCancelable(false) lateinit var cancel: () -> Unit - val fragment by lazy { getCurrentGroupFragment() } - val results = Collections.synchronizedList(mutableListOf()) + lateinit var minimize: () -> Unit + + val dialogStatus = AtomicInteger(0) // 1: hidden 2: cancelled + var notification: ConnectionTestNotification? = null + + val results: MutableSet = ConcurrentHashMap.newKeySet() var proxyN = 0 val finishedN = AtomicInteger(0) - suspend fun insert(profile: ProxyEntity?) { - results.add(profile) - } + fun update(profile: ProxyEntity) { + if (dialogStatus.get() != 2) { + results.add(profile) + } + runOnMainDispatcher { + val context = context ?: return@runOnMainDispatcher + val progress = finishedN.addAndGet(1) + val status = dialogStatus.get() + notification?.updateNotification( + progress, + proxyN, + progress >= proxyN || status == 2 + ) + if (status >= 1) return@runOnMainDispatcher + if (!isAdded) return@runOnMainDispatcher - suspend fun update(profile: ProxyEntity) { - fragment?.configurationListView?.post { - val context = context ?: return@post - if (!isAdded) return@post + // refresh dialog var profileStatusText: String? = null var profileStatusColor = 0 @@ -670,64 +683,46 @@ class ConfigurationFragment @JvmOverloads constructor( } binding.nowTesting.text = text - binding.progress.text = "${finishedN.addAndGet(1)} / $proxyN" + binding.progress.text = "$progress / $proxyN" } } } - fun stopService() { - if (DataStore.serviceState.started) SagerNet.stopService() - } - @OptIn(DelicateCoroutinesApi::class) @Suppress("EXPERIMENTAL_API_USAGE") fun pingTest(icmpPing: Boolean) { + if (DataStore.runningTest) return else DataStore.runningTest = true val test = TestDialog() - val testJobs = mutableListOf() val dialog = test.builder.show() + val testJobs = mutableListOf() + val group = DataStore.currentGroup() + val mainJob = runOnDefaultDispatcher { - if (DataStore.serviceState.started) { - stopService() - delay(500) // wait for service stop + val profilesList = SagerDatabase.proxyDao.getByGroup(group.id).filter { + if (icmpPing) { + if (it.requireBean().canICMPing()) { + return@filter true + } + } else { + if (it.requireBean().canTCPing()) { + return@filter true + } + } + return@filter false } - val group = DataStore.currentGroup() - val profilesUnfiltered = SagerDatabase.proxyDao.getByGroup(group.id) - test.proxyN = profilesUnfiltered.size - val profiles = ConcurrentLinkedQueue(profilesUnfiltered) - val testPool = newFixedThreadPoolContext( - DataStore.connectionTestConcurrent, - "pingTest" - ) + test.proxyN = profilesList.size + val profiles = ConcurrentLinkedQueue(profilesList) repeat(DataStore.connectionTestConcurrent) { - testJobs.add(launch(testPool) { + testJobs.add(launch(Dispatchers.IO) { while (isActive) { val profile = profiles.poll() ?: break - if (icmpPing) { - if (!profile.requireBean().canICMPing()) { - profile.status = -1 - profile.error = - app.getString(R.string.connection_test_icmp_ping_unavailable) - test.insert(profile) - continue - } - } else { - if (!profile.requireBean().canTCPing()) { - profile.status = -1 - profile.error = - app.getString(R.string.connection_test_tcp_ping_unavailable) - test.insert(profile) - continue - } - } - profile.status = 0 - test.insert(profile) var address = profile.requireBean().serverAddress if (!address.isIpAddress()) { try { - InetAddress.getAllByName(address).apply { + SagerNet.underlyingNetwork!!.getAllByName(address).apply { if (isNotEmpty()) { address = this[0].hostAddress } @@ -746,7 +741,9 @@ class ConfigurationFragment @JvmOverloads constructor( if (icmpPing) { // removed } else { - val socket = Socket() + val socket = + SagerNet.underlyingNetwork?.socketFactory?.createSocket() + ?: Socket() try { socket.soTimeout = 3000 socket.bind(InetSocketAddress(0)) @@ -802,15 +799,18 @@ class ConfigurationFragment @JvmOverloads constructor( } testJobs.joinAll() - testPool.close() - onMainDispatcher { - dialog.dismiss() + runOnMainDispatcher { + test.cancel() } } test.cancel = { + test.dialogStatus.set(2) + dialog.dismiss() runOnDefaultDispatcher { - test.results.filterNotNull().forEach { + mainJob.cancel() + testJobs.forEach { it.cancel() } + test.results.forEach { try { ProfileManager.updateProfile(it) } catch (e: Exception) { @@ -818,34 +818,37 @@ class ConfigurationFragment @JvmOverloads constructor( } } GroupManager.postReload(DataStore.currentGroupId()) - mainJob.cancel() - testJobs.forEach { it.cancel() } + DataStore.runningTest = false } } + test.minimize = { + test.dialogStatus.set(1) + test.notification = ConnectionTestNotification( + dialog.context, + "[${group.displayName()}] ${getString(R.string.connection_test)}" + ) + dialog.hide() + } } @OptIn(DelicateCoroutinesApi::class) fun urlTest() { + if (DataStore.runningTest) return else DataStore.runningTest = true val test = TestDialog() val dialog = test.builder.show() val testJobs = mutableListOf() + val group = DataStore.currentGroup() val mainJob = runOnDefaultDispatcher { - val group = DataStore.currentGroup() - val profilesUnfiltered = SagerDatabase.proxyDao.getByGroup(group.id) - test.proxyN = profilesUnfiltered.size - val profiles = ConcurrentLinkedQueue(profilesUnfiltered) - val testPool = newFixedThreadPoolContext( - DataStore.connectionTestConcurrent, - "urlTest" - ) + val profilesList = SagerDatabase.proxyDao.getByGroup(group.id) + test.proxyN = profilesList.size + val profiles = ConcurrentLinkedQueue(profilesList) repeat(DataStore.connectionTestConcurrent) { - testJobs.add(launch(testPool) { + testJobs.add(launch(Dispatchers.IO) { val urlTest = UrlTest() // note: this is NOT in bg process while (isActive) { val profile = profiles.poll() ?: break profile.status = 0 - test.insert(profile) try { val result = urlTest.doTest(profile) @@ -866,13 +869,17 @@ class ConfigurationFragment @JvmOverloads constructor( testJobs.joinAll() - onMainDispatcher { - dialog.dismiss() + runOnMainDispatcher { + test.cancel() } } test.cancel = { + test.dialogStatus.set(2) + dialog.dismiss() runOnDefaultDispatcher { - test.results.filterNotNull().forEach { + mainJob.cancel() + testJobs.forEach { it.cancel() } + test.results.forEach { try { ProfileManager.updateProfile(it) } catch (e: Exception) { @@ -880,10 +887,17 @@ class ConfigurationFragment @JvmOverloads constructor( } } GroupManager.postReload(DataStore.currentGroupId()) - mainJob.cancel() - testJobs.forEach { it.cancel() } + DataStore.runningTest = false } } + test.minimize = { + test.dialogStatus.set(1) + test.notification = ConnectionTestNotification( + dialog.context, + "[${group.displayName()}] ${getString(R.string.connection_test)}" + ) + dialog.hide() + } } inner class GroupPagerAdapter : FragmentStateAdapter(this), @@ -1412,7 +1426,6 @@ class ConfigurationFragment @JvmOverloads constructor( fun reloadProfiles() { var newProfiles = SagerDatabase.proxyDao.getByGroup(proxyGroup.id) - val subscription = proxyGroup.subscription when (proxyGroup.order) { GroupOrder.BY_NAME -> { newProfiles = newProfiles.sortedBy { it.displayName() } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/DebugFragment.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/DebugFragment.kt deleted file mode 100644 index a5d33a35fa..0000000000 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/DebugFragment.kt +++ /dev/null @@ -1,28 +0,0 @@ -package io.nekohasekai.sagernet.ui - -import android.os.Bundle -import android.view.View -import io.nekohasekai.sagernet.R -import io.nekohasekai.sagernet.database.DataStore -import io.nekohasekai.sagernet.databinding.LayoutDebugBinding -import io.nekohasekai.sagernet.ktx.snackbar - -class DebugFragment : NamedFragment(R.layout.layout_debug) { - - override fun name0() = "Debug" - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val binding = LayoutDebugBinding.bind(view) - - binding.debugCrash.setOnClickListener { - error("test crash") - } - binding.resetSettings.setOnClickListener { - DataStore.configurationStore.reset() - snackbar("Cleared").show() - } - } - -} \ No newline at end of file diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/LogcatFragment.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/LogcatFragment.kt index ef22f30b4e..bb4a082d74 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/LogcatFragment.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/LogcatFragment.kt @@ -9,9 +9,10 @@ import android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE import android.text.style.ForegroundColorSpan import android.view.MenuItem import android.view.View -import android.widget.ScrollView +import android.view.ViewGroup import androidx.appcompat.widget.Toolbar import androidx.core.view.ViewCompat +import androidx.core.view.doOnLayout import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.databinding.LayoutLogcatBinding import io.nekohasekai.sagernet.ktx.* @@ -41,7 +42,6 @@ class LogcatFragment : ToolbarFragment(R.layout.layout_logcat), ViewCompat.setOnApplyWindowInsetsListener(binding.root, ListListener) reloadSession() - // TODO new logcat } private fun getColorForLine(line: String): ForegroundColorSpan { @@ -76,8 +76,15 @@ class LogcatFragment : ToolbarFragment(R.layout.layout_logcat), } binding.textview.text = span - binding.scroolview.post { - binding.scroolview.fullScroll(ScrollView.FOCUS_DOWN) + // 阻止自动滚动/焦点干扰 + binding.scroolview.descendantFocusability = ViewGroup.FOCUS_BLOCK_DESCENDANTS + binding.textview.isFocusable = false + binding.textview.isFocusableInTouchMode = false + binding.textview.clearFocus() + + // 等 textview 完成最终 layout 再滚动到底部 + binding.textview.doOnLayout { + binding.scroolview.scrollTo(0, binding.textview.height) } } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/MainActivity.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/MainActivity.kt index 9e63cabdf7..a60012e10a 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/MainActivity.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/MainActivity.kt @@ -18,6 +18,7 @@ import androidx.preference.PreferenceDataStore import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.navigation.NavigationView import com.google.android.material.snackbar.Snackbar +import io.nekohasekai.sagernet.BuildConfig import io.nekohasekai.sagernet.GroupType import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.R @@ -117,7 +118,8 @@ class MainActivity : ThemedActivity(), } if (isPreview) { - MaterialAlertDialogBuilder(this).setTitle(R.string.preview_version) + MaterialAlertDialogBuilder(this) + .setTitle(BuildConfig.PRE_VERSION_NAME) .setMessage(R.string.preview_version_hint) .setPositiveButton(android.R.string.ok, null) .show() diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/RouteSettingsActivity.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/RouteSettingsActivity.kt index 825d24ae57..aaa062de30 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/RouteSettingsActivity.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/RouteSettingsActivity.kt @@ -39,6 +39,7 @@ import io.nekohasekai.sagernet.widget.AppListPreference import io.nekohasekai.sagernet.widget.ListListener import io.nekohasekai.sagernet.widget.OutboundPreference import kotlinx.parcelize.Parcelize +import moe.matsuri.nb4a.ui.EditConfigPreference @Suppress("UNCHECKED_CAST") class RouteSettingsActivity( @@ -57,6 +58,7 @@ class RouteSettingsActivity( fun RuleEntity.init() { DataStore.routeName = name + DataStore.serverConfig = config DataStore.routeDomain = domains DataStore.routeIP = ip DataStore.routePort = port @@ -76,6 +78,7 @@ class RouteSettingsActivity( fun RuleEntity.serialize() { name = DataStore.routeName + config = DataStore.serverConfig domains = DataStore.routeDomain ip = DataStore.routeIP port = DataStore.routePort @@ -96,12 +99,10 @@ class RouteSettingsActivity( } } + private lateinit var editConfigPreference: EditConfigPreference + fun needSave(): Boolean { - if (!DataStore.dirty) return false - if (DataStore.routePackages.isBlank() && DataStore.routeDomain.isBlank() && DataStore.routeIP.isBlank() && DataStore.routePort.isBlank() && DataStore.routeSourcePort.isBlank() && DataStore.routeNetwork.isBlank() && DataStore.routeSource.isBlank() && DataStore.routeProtocol.isBlank()) { - return false - } - return true + return DataStore.dirty } fun PreferenceFragmentCompat.createPreferences( @@ -109,6 +110,16 @@ class RouteSettingsActivity( rootKey: String?, ) { addPreferencesFromResource(R.xml.route_preferences) + + editConfigPreference = findPreference(Key.SERVER_CONFIG)!! + } + + override fun onResume() { + super.onResume() + + if (::editConfigPreference.isInitialized) { + editConfigPreference.notifyChanged() + } } val selectProfileForAdd = registerForActivityResult( @@ -163,7 +174,7 @@ class RouteSettingsActivity( } } - fun PreferenceFragmentCompat.displayPreferenceDialog(preference: Preference): Boolean { + fun displayPreferenceDialog(preference: Preference): Boolean { return false } diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/SettingsPreferenceFragment.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/SettingsPreferenceFragment.kt index 5c91718c97..18d6454557 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/SettingsPreferenceFragment.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/SettingsPreferenceFragment.kt @@ -22,6 +22,9 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() { private lateinit var isProxyApps: SwitchPreference + private lateinit var globalCustomConfig: EditConfigPreference + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -77,6 +80,8 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() { val logLevel = findPreference(Key.LOG_LEVEL)!! val mtu = findPreference(Key.MTU)!! + globalCustomConfig = findPreference(Key.GLOBAL_CUSTOM_CONFIG)!! + globalCustomConfig.useConfigStore(Key.GLOBAL_CUSTOM_CONFIG) logLevel.dialogLayoutResource = R.layout.layout_loglevel_help logLevel.setOnPreferenceChangeListener { _, _ -> @@ -162,7 +167,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() { resolveDestination.onPreferenceChangeListener = reloadListener tunImplementation.onPreferenceChangeListener = reloadListener acquireWakeLock.onPreferenceChangeListener = reloadListener - + globalCustomConfig.onPreferenceChangeListener = reloadListener } override fun onResume() { @@ -171,6 +176,9 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() { if (::isProxyApps.isInitialized) { isProxyApps.isChecked = DataStore.proxyApps } + if (::globalCustomConfig.isInitialized) { + globalCustomConfig.notifyChanged() + } } } \ No newline at end of file diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ToolsFragment.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ToolsFragment.kt index bf73ca1d91..32738ea98f 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ToolsFragment.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/ToolsFragment.kt @@ -7,7 +7,6 @@ import androidx.viewpager2.adapter.FragmentStateAdapter import com.google.android.material.tabs.TabLayoutMediator import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.databinding.LayoutToolsBinding -import io.nekohasekai.sagernet.ktx.isExpert class ToolsFragment : ToolbarFragment(R.layout.layout_tools) { @@ -19,8 +18,6 @@ class ToolsFragment : ToolbarFragment(R.layout.layout_tools) { tools.add(NetworkFragment()) tools.add(BackupFragment()) - if (isExpert) tools.add(DebugFragment()) - val binding = LayoutToolsBinding.bind(view) binding.toolsPager.adapter = ToolsAdapter(tools) diff --git a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ConfigEditActivity.kt b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ConfigEditActivity.kt index a8f3ab26bc..ac8f046a85 100644 --- a/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ConfigEditActivity.kt +++ b/nekobox-android/app/src/main/java/io/nekohasekai/sagernet/ui/profile/ConfigEditActivity.kt @@ -33,6 +33,7 @@ class ConfigEditActivity : ThemedActivity() { var dirty = false var key = Key.SERVER_CONFIG + var useConfigStore = false class UnsavedChangesDialogFragment : AlertDialogFragment() { override fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener) { @@ -55,6 +56,7 @@ class ConfigEditActivity : ThemedActivity() { intent?.extras?.apply { getString("key")?.let { key = it } + getString("useConfigStore")?.let { useConfigStore = true } } binding = LayoutEditConfigBinding.inflate(layoutInflater) @@ -70,7 +72,11 @@ class ConfigEditActivity : ThemedActivity() { binding.editor.apply { language = JsonLanguage() setHorizontallyScrolling(true) - setTextContent(DataStore.profileCacheStore.getString(key)!!) + if (useConfigStore) { + setTextContent(DataStore.configurationStore.getString(key) ?: "") + } else { + setTextContent(DataStore.profileCacheStore.getString(key) ?: "") + } addTextChangedListener { if (!dirty) { dirty = true @@ -142,7 +148,11 @@ class ConfigEditActivity : ThemedActivity() { fun saveAndExit() { formatText()?.let { - DataStore.profileCacheStore.putString(key, it) + if (useConfigStore) { + DataStore.configurationStore.putString(key, it) + } else { + DataStore.profileCacheStore.putString(key, it) + } finish() } } diff --git a/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptions.java b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptions.java index 82572f574f..05f89275ff 100644 --- a/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptions.java +++ b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptions.java @@ -1,19 +1,97 @@ package moe.matsuri.nb4a; -import static moe.matsuri.nb4a.utils.JavaUtil.gson; - +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.ToNumberPolicy; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; +import java.util.HashMap; import java.util.List; import java.util.Map; +import moe.matsuri.nb4a.utils.Util; + public class SingBoxOptions { // base + private static final Gson gsonSingbox = new GsonBuilder() + .registerTypeHierarchyAdapter(SingBoxOption.class, new SingBoxOptionSerializer()) + .setPrettyPrinting() + .setNumberToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) + .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) + .setLenient() + .disableHtmlEscaping() + .create(); + public static class SingBoxOption { + + public transient Map _hack_config_map; // 仍然用普通json方式合并,所以Object内不要使用 _hack + + public transient String _hack_custom_config; + + public SingBoxOption() { + _hack_config_map = new HashMap<>(); + } + public Map asMap() { - return gson.fromJson(gson.toJson(this), Map.class); + return gsonSingbox.fromJson(gsonSingbox.toJson(this), Map.class); + } + + } + + public static final class CustomSingBoxOption extends SingBoxOption { + + public transient String config; + + public CustomSingBoxOption(String config) { + super(); + this.config = config; + } + + public Map getBasicMap() { + Map map = gsonSingbox.fromJson(config, Map.class); + if (map == null) { + map = new HashMap<>(); + } + return map; + } + } + + // 自定义序列化器 + public static class SingBoxOptionSerializer implements JsonSerializer { + @Override + public JsonElement serialize(SingBoxOption src, Type typeOfSrc, JsonSerializationContext context) { + // 拿到原始的 delegate(默认序列化器) + TypeAdapter delegate = gsonSingbox.getDelegateAdapter( + new TypeAdapterFactory() { + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + return null; // 返回 null,表示只作为“跳过当前自定义”的 marker + } + }, + TypeToken.get(src.getClass()) + ); + Map map; + if (src instanceof CustomSingBoxOption) { + map = ((CustomSingBoxOption) src).getBasicMap(); + } else { + map = gsonSingbox.fromJson(((TypeAdapter) delegate).toJson(src), Map.class); + } + if (src._hack_config_map != null && !src._hack_config_map.isEmpty()) { + Util.INSTANCE.mergeMap(map, src._hack_config_map); + } + if (src._hack_custom_config != null && !src._hack_custom_config.isBlank()) { + Util.INSTANCE.mergeJSON(map, src._hack_custom_config); + } + return gsonSingbox.toJsonTree(map); } } @@ -33,7 +111,7 @@ public class SingBoxOptions { public List inbounds; - public List> outbounds; + public List outbounds; public RouteOptions route; diff --git a/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptionsUtil.kt b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptionsUtil.kt index 19f733bddb..d3971b2b27 100644 --- a/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptionsUtil.kt +++ b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/SingBoxOptionsUtil.kt @@ -157,5 +157,7 @@ fun SingBoxOptions.Rule_DefaultOptions.checkEmpty(): Boolean { if (port?.isNotEmpty() == true) return false if (port_range?.isNotEmpty() == true) return false if (source_ip_cidr?.isNotEmpty() == true) return false + // + if (!_hack_custom_config.isNullOrBlank()) return false return true } diff --git a/nekobox-android/app/src/main/java/moe/matsuri/nb4a/ui/ConnectionTestNotification.kt b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/ui/ConnectionTestNotification.kt new file mode 100644 index 0000000000..31bc7a1935 --- /dev/null +++ b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/ui/ConnectionTestNotification.kt @@ -0,0 +1,29 @@ +package moe.matsuri.nb4a.ui + +import android.content.Context +import androidx.core.app.NotificationCompat +import io.nekohasekai.sagernet.R +import io.nekohasekai.sagernet.SagerNet +import io.nekohasekai.sagernet.ktx.Logs + +class ConnectionTestNotification(val context: Context, val title: String) { + private val channelId = "connection-test" + private val notificationId = 1001 + + fun updateNotification(progress: Int, max: Int, finished: Boolean) { + try { + if (finished) { + SagerNet.notification.cancel(notificationId) + return + } + val builder = NotificationCompat.Builder(context, channelId) + .setSmallIcon(R.drawable.ic_service_active) + .setContentTitle(title) + .setOnlyAlertOnce(true) + .setContentText("$progress / $max").setProgress(max, progress, false) + SagerNet.notification.notify(notificationId, builder.build()) + } catch (e: Exception) { + Logs.w(e) + } + } +} \ No newline at end of file diff --git a/nekobox-android/app/src/main/java/moe/matsuri/nb4a/ui/EditConfigPreference.kt b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/ui/EditConfigPreference.kt index 6b2ea819af..1292ed5c5b 100644 --- a/nekobox-android/app/src/main/java/moe/matsuri/nb4a/ui/EditConfigPreference.kt +++ b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/ui/EditConfigPreference.kt @@ -4,8 +4,10 @@ import android.content.Context import android.content.Intent import android.util.AttributeSet import androidx.preference.Preference +import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.database.DataStore +import io.nekohasekai.sagernet.ktx.Logs import io.nekohasekai.sagernet.ktx.app import io.nekohasekai.sagernet.ui.profile.ConfigEditActivity @@ -26,9 +28,27 @@ class EditConfigPreference : Preference { intent = Intent(context, ConfigEditActivity::class.java) } + var configKey = Key.SERVER_CONFIG + var useConfigStore = false + + fun useConfigStore(key: String) { + try { + this.configKey = key + useConfigStore = true + intent = intent!!.apply { + putExtra("useConfigStore", "1") + putExtra("key", key) + } + } catch (e: Exception) { + Logs.w(e) + } + } + override fun getSummary(): CharSequence { - val config = DataStore.serverConfig - return if (DataStore.serverConfig.isBlank()) { + val config = + (if (useConfigStore) DataStore.configurationStore.getString(configKey) else DataStore.serverConfig) + ?: "" + return if (config.isBlank()) { return app.resources.getString(androidx.preference.R.string.not_set) } else { app.resources.getString(R.string.lines, config.split('\n').size) diff --git a/nekobox-android/app/src/main/java/moe/matsuri/nb4a/utils/Util.kt b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/utils/Util.kt index 35df4ee61b..c5ae09abbf 100644 --- a/nekobox-android/app/src/main/java/moe/matsuri/nb4a/utils/Util.kt +++ b/nekobox-android/app/src/main/java/moe/matsuri/nb4a/utils/Util.kt @@ -5,6 +5,8 @@ import android.content.Context import android.util.Base64 import libcore.StringBox import java.io.ByteArrayOutputStream +import java.net.URLDecoder +import java.nio.charset.StandardCharsets import java.text.SimpleDateFormat import java.util.* import java.util.zip.Deflater @@ -132,12 +134,12 @@ object Util { } else if (v is List<*>) { if (k.startsWith("+")) { // prepend val dstKey = k.removePrefix("+") - var currentList = (dst[dstKey] as List<*>).toMutableList() + var currentList = (dst[dstKey] as? List<*>)?.toMutableList() ?: mutableListOf() currentList = (v + currentList).toMutableList() dst[dstKey] = currentList } else if (k.endsWith("+")) { // append val dstKey = k.removeSuffix("+") - var currentList = (dst[dstKey] as List<*>).toMutableList() + var currentList = (dst[dstKey] as? List<*>)?.toMutableList() ?: mutableListOf() currentList = (currentList + v).toMutableList() dst[dstKey] = currentList } else { @@ -150,7 +152,7 @@ object Util { return dst } - fun mergeJSON(j: String, dst: MutableMap) { + fun mergeJSON(dst: MutableMap, j: String) { if (j.isBlank()) return val src = JavaUtil.gson.fromJson(j, dst.javaClass) mergeMap(dst, src) @@ -188,4 +190,11 @@ object Util { } return "" } + + fun decodeFilename(headerValue: String): String { + val regex = Regex("filename\\*=[^']*''(.+)") + val match = regex.find(headerValue) + val encoded = match?.groupValues?.get(1) ?: "" + return URLDecoder.decode(encoded, StandardCharsets.UTF_8.name()) + } } diff --git a/nekobox-android/app/src/main/res/layout/layout_backup.xml b/nekobox-android/app/src/main/res/layout/layout_backup.xml index fb61aaf98b..81a7decee0 100644 --- a/nekobox-android/app/src/main/res/layout/layout_backup.xml +++ b/nekobox-android/app/src/main/res/layout/layout_backup.xml @@ -5,6 +5,14 @@ android:orientation="vertical" android:padding="16dp"> +