From 1fc4f5ee6caed206028e736948b2b51633b8f903 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 19:51:10 +0000 Subject: [PATCH 01/11] build(deps): bump actions/upload-artifact from 4.6.2 to 7.0.1 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.2 to 7.0.1. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/ea165f8d65b6e75b540449e92b4886f43607fa02...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/nightly.yml | 2 +- .github/workflows/performance-evidence.yml | 2 +- .github/workflows/pr-quick.yml | 2 +- .github/workflows/release-gate.yml | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index fd0f0b5..a880e09 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -147,7 +147,7 @@ jobs: - name: Upload Chaos Report if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: chaos-nightly-2h-${{ runner.os }} path: | diff --git a/.github/workflows/performance-evidence.yml b/.github/workflows/performance-evidence.yml index 6198384..f1d975a 100644 --- a/.github/workflows/performance-evidence.yml +++ b/.github/workflows/performance-evidence.yml @@ -42,7 +42,7 @@ jobs: - name: Upload raw smoke evidence if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: sharplink-performance-smoke-${{ github.sha }} path: artifacts/performance/smoke/${{ github.sha }} diff --git a/.github/workflows/pr-quick.yml b/.github/workflows/pr-quick.yml index 30a7bbd..8de881b 100644 --- a/.github/workflows/pr-quick.yml +++ b/.github/workflows/pr-quick.yml @@ -91,7 +91,7 @@ jobs: - name: Upload Chaos Report if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: chaos-pr-smoke path: | diff --git a/.github/workflows/release-gate.yml b/.github/workflows/release-gate.yml index b77370b..58f0f30 100644 --- a/.github/workflows/release-gate.yml +++ b/.github/workflows/release-gate.yml @@ -63,7 +63,7 @@ jobs: - name: Upload Integration Diagnostics if: failure() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: integration-${{ runner.os }}-diagnostics path: artifacts/test-results/integration-${{ runner.os }} @@ -156,7 +156,7 @@ jobs: test -n "$(find artifacts/nuget -name '*.nupkg' -type f)" - name: Upload NuGet artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: nuget-packages path: | @@ -194,7 +194,7 @@ jobs: - name: Upload Chaos Report if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: chaos-release-smoke-${{ runner.os }} path: | From 5b89d5c42bdead87ec42c129ade14bcf76c84ad4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 19:51:17 +0000 Subject: [PATCH 02/11] build(deps): bump actions/setup-dotnet from 4.3.1 to 6.0.0 Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4.3.1 to 6.0.0. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/67a3573c9a986a3f9c594539f4ab511d57bb3ce9...a98b56852c35b8e3190ac28c8c2271da59106c68) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/nightly.yml | 8 ++++---- .github/workflows/performance-evidence.yml | 2 +- .github/workflows/pr-quick.yml | 2 +- .github/workflows/release-gate.yml | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index fd0f0b5..09b8ae1 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup .NET - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x @@ -82,7 +82,7 @@ jobs: uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup .NET - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x @@ -103,7 +103,7 @@ jobs: uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup .NET - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x @@ -124,7 +124,7 @@ jobs: uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup .NET - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x diff --git a/.github/workflows/performance-evidence.yml b/.github/workflows/performance-evidence.yml index 6198384..1c43420 100644 --- a/.github/workflows/performance-evidence.yml +++ b/.github/workflows/performance-evidence.yml @@ -25,7 +25,7 @@ jobs: uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup .NET - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x diff --git a/.github/workflows/pr-quick.yml b/.github/workflows/pr-quick.yml index 30a7bbd..49292ac 100644 --- a/.github/workflows/pr-quick.yml +++ b/.github/workflows/pr-quick.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup .NET - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x diff --git a/.github/workflows/release-gate.yml b/.github/workflows/release-gate.yml index b77370b..e544764 100644 --- a/.github/workflows/release-gate.yml +++ b/.github/workflows/release-gate.yml @@ -28,7 +28,7 @@ jobs: uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup .NET - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x @@ -103,7 +103,7 @@ jobs: uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup .NET - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x @@ -124,7 +124,7 @@ jobs: uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup .NET - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x @@ -177,7 +177,7 @@ jobs: uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup .NET - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x @@ -226,7 +226,7 @@ jobs: uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Setup .NET - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.x From c70f091f21a98741018e8596b179ec86e3835e50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 19:53:45 +0000 Subject: [PATCH 03/11] build(deps): bump actions/download-artifact from 4.3.0 to 8.0.1 Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.3.0 to 8.0.1. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/d3f86a106a0bac45b974a628896c90dbdf5c8093...3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 8.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release-gate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-gate.yml b/.github/workflows/release-gate.yml index b77370b..f1b801e 100644 --- a/.github/workflows/release-gate.yml +++ b/.github/workflows/release-gate.yml @@ -231,7 +231,7 @@ jobs: dotnet-version: 10.0.x - name: Download release-gated packages - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: nuget-packages path: artifacts/nuget From 55b6486a44146d7bd0aa8d015b2966c63ab278fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 19:53:51 +0000 Subject: [PATCH 04/11] build(deps): bump actions/checkout from 4.4.0 to 7.0.1 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.4.0 to 7.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/11d5960a326750d5838078e36cf38b85af677262...3d3c42e5aac5ba805825da76410c181273ba90b1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 2 +- .github/workflows/nightly.yml | 8 ++++---- .github/workflows/performance-evidence.yml | 2 +- .github/workflows/pr-quick.yml | 2 +- .github/workflows/release-gate.yml | 10 +++++----- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index efb89ac..e9dc2e5 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -26,7 +26,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Initialize CodeQL uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index fd0f0b5..76a8b12 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -21,7 +21,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: '1' steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 @@ -79,7 +79,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: '1' steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 @@ -100,7 +100,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: '1' steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 @@ -121,7 +121,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: '1' steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 diff --git a/.github/workflows/performance-evidence.yml b/.github/workflows/performance-evidence.yml index 6198384..fa70018 100644 --- a/.github/workflows/performance-evidence.yml +++ b/.github/workflows/performance-evidence.yml @@ -22,7 +22,7 @@ jobs: SHARPLINK_MATRIX_OUTPUT: ${{ github.workspace }}/artifacts/performance/smoke/${{ github.sha }} steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 diff --git a/.github/workflows/pr-quick.yml b/.github/workflows/pr-quick.yml index 30a7bbd..7f12f1b 100644 --- a/.github/workflows/pr-quick.yml +++ b/.github/workflows/pr-quick.yml @@ -20,7 +20,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: '1' steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 diff --git a/.github/workflows/release-gate.yml b/.github/workflows/release-gate.yml index b77370b..8565851 100644 --- a/.github/workflows/release-gate.yml +++ b/.github/workflows/release-gate.yml @@ -25,7 +25,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: '1' steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 @@ -100,7 +100,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: '1' steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 @@ -121,7 +121,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: '1' steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 @@ -174,7 +174,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: '1' steps: - name: Checkout - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 @@ -223,7 +223,7 @@ jobs: contents: read steps: - name: Checkout exact tag - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 From dbf7b38d67e01806ac3819d83fb1a27ba497bdb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 19:59:51 +0000 Subject: [PATCH 05/11] Bump the microsoft-extensions group with 8 updates Bumps Microsoft.Extensions.DependencyInjection from 10.0.2 to 10.0.10 Bumps Microsoft.Extensions.DependencyInjection.Abstractions from 10.0.2 to 10.0.10 Bumps Microsoft.Extensions.Diagnostics.HealthChecks from 10.0.2 to 10.0.10 Bumps Microsoft.Extensions.Hosting from 10.0.2 to 10.0.10 Bumps Microsoft.Extensions.Hosting.Abstractions from 10.0.2 to 10.0.10 Bumps Microsoft.Extensions.Logging from 10.0.2 to 10.0.10 Bumps Microsoft.Extensions.Logging.Abstractions from 10.0.2 to 10.0.10 Bumps Microsoft.Extensions.Logging.Console from 10.0.2 to 10.0.10 --- updated-dependencies: - dependency-name: Microsoft.Extensions.DependencyInjection dependency-version: 10.0.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft-extensions - dependency-name: Microsoft.Extensions.DependencyInjection.Abstractions dependency-version: 10.0.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft-extensions - dependency-name: Microsoft.Extensions.Diagnostics.HealthChecks dependency-version: 10.0.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft-extensions - dependency-name: Microsoft.Extensions.Hosting.Abstractions dependency-version: 10.0.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft-extensions - dependency-name: Microsoft.Extensions.Hosting dependency-version: 10.0.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft-extensions - dependency-name: Microsoft.Extensions.Logging dependency-version: 10.0.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft-extensions - dependency-name: Microsoft.Extensions.Logging.Abstractions dependency-version: 10.0.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft-extensions - dependency-name: Microsoft.Extensions.Logging.Console dependency-version: 10.0.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: microsoft-extensions ... Signed-off-by: dependabot[bot] --- Directory.Packages.props | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 21ba259..73bc64e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -18,15 +18,15 @@ - - + + - - - - - - + + + + + + From f6c4b825e205b08d4f32da50ed45cfca53b99ad6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 20:02:43 +0000 Subject: [PATCH 06/11] Bump the roslyn group with 2 updates Bumps Microsoft.CodeAnalysis.Analyzers from 3.11.0 to 5.6.0 Bumps Microsoft.CodeAnalysis.CSharp from 5.0.0 to 5.6.0 --- updated-dependencies: - dependency-name: Microsoft.CodeAnalysis.Analyzers dependency-version: 5.6.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: roslyn - dependency-name: Microsoft.CodeAnalysis.CSharp dependency-version: 5.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: roslyn ... Signed-off-by: dependabot[bot] --- Directory.Packages.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 21ba259..1c96039 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,12 +4,12 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + From f2fbb3ee9af13792c449e30b4fb827c5b58a8ea7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 20:05:50 +0000 Subject: [PATCH 07/11] Bump the testing group with 1 update Bumps TUnit from 1.14.0 to 1.63.0 --- updated-dependencies: - dependency-name: TUnit dependency-version: 1.63.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: testing ... Signed-off-by: dependabot[bot] --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 21ba259..ec748b4 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -27,6 +27,6 @@ - + From 2172c907e17e56f06e5a134bdf706d696144d00b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 20:08:54 +0000 Subject: [PATCH 08/11] Bump System.Text.Json from 10.0.2 to 10.0.10 --- updated-dependencies: - dependency-name: System.Text.Json dependency-version: 10.0.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 21ba259..998aa45 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,7 +13,7 @@ - + From 620ef236e4013c8c7b3d94b3fba9b7ba31ad7e79 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 20:09:21 +0000 Subject: [PATCH 09/11] Bump System.Threading.RateLimiting from 10.0.2 to 10.0.10 --- updated-dependencies: - dependency-name: System.Threading.RateLimiting dependency-version: 10.0.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 21ba259..635a02f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -14,7 +14,7 @@ - + From b21274a68c2fc21512c05db34402c33924195de5 Mon Sep 17 00:00:00 2001 From: sunsi Date: Sun, 2 Aug 2026 13:21:36 +0800 Subject: [PATCH 10/11] release: prepare SharpLink 1.0.1 --- CHANGELOG.md | 16 +++++ Directory.Build.props | 4 +- README.md | 28 ++++----- assets/sharplink-icon.png | Bin 0 -> 39137 bytes doc/architecture.md | 18 ++++-- doc/getting-started.md | 2 +- doc/index.md | 2 +- doc/releasing.md | 4 +- eng/verify-packages.sh | 9 +++ .../Sdk}/IService.cs | 0 .../Sdk}/IdempotentAttribute.cs | 0 .../Sdk}/NonCancellableAttribute.cs | 0 .../Sdk}/OnewayAttribute.cs | 0 .../Sdk}/RpcCodecAdapterAttribute.cs | 0 .../RpcCodecAdapterRegistrationAttribute.cs | 0 .../Sdk}/RpcContractAttribute.cs | 0 .../Sdk}/RpcIgnoreAttribute.cs | 0 .../Sdk}/RpcMemberAttribute.cs | 0 .../Sdk}/RpcRequiredAttribute.cs | 0 .../Sdk}/RpcSerializableAttribute.cs | 0 .../Sdk}/RpcServiceAttribute.cs | 0 .../Sdk}/RpcUnionCaseAttribute.cs | 0 .../Sdk}/SharpLinkCallOptions.cs | 0 ...arpLinkClusterContractAssemblyAttribute.cs | 0 .../Sdk}/SharpLinkMetadata.cs | 0 .../Sdk}/SharpLinkRpcContractsAttribute.cs | 0 .../Sdk}/SharpLinkServiceLifetime.cs | 0 .../Sdk}/TimeoutAttribute.cs | 0 .../SharpLink.Abstractions.csproj | 2 +- src/SharpLink.Sdk/SharpLink.Sdk.csproj | 1 + src/SharpLink.Sdk/TypeForwards.cs | 22 +++++++ .../SharpLink.PackageSmoke.csproj | 4 ++ .../EchoContract.cs | 9 +++ .../SharpLink.SdkOnlyPackageSmoke.csproj | 14 +++++ .../SdkTypeForwardingTests.cs | 59 ++++++++++++++++++ .../SharpLink.UnitTests.csproj | 1 + 36 files changed, 167 insertions(+), 28 deletions(-) create mode 100644 assets/sharplink-icon.png rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/IService.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/IdempotentAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/NonCancellableAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/OnewayAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/RpcCodecAdapterAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/RpcCodecAdapterRegistrationAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/RpcContractAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/RpcIgnoreAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/RpcMemberAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/RpcRequiredAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/RpcSerializableAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/RpcServiceAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/RpcUnionCaseAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/SharpLinkCallOptions.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/SharpLinkClusterContractAssemblyAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/SharpLinkMetadata.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/SharpLinkRpcContractsAttribute.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/SharpLinkServiceLifetime.cs (100%) rename src/{SharpLink.Sdk => SharpLink.Abstractions/Sdk}/TimeoutAttribute.cs (100%) create mode 100644 src/SharpLink.Sdk/TypeForwards.cs create mode 100644 test/SharpLink.SdkOnlyPackageSmoke/EchoContract.cs create mode 100644 test/SharpLink.SdkOnlyPackageSmoke/SharpLink.SdkOnlyPackageSmoke.csproj create mode 100644 test/SharpLink.UnitTests/SdkTypeForwardingTests.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index c9b5140..40214a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ ## [Unreleased] +## [1.0.1] - 2026-08-02 + +### Fixed + +- A standalone contract project can now reference only `SharpLink.Sdk`. The package brings the required runtime and abstractions transitively, so generated Proxy, Stub, Codec, and Manifest sources no longer fail with missing SharpLink namespaces or types. +- Contract marker types now live in `SharpLink.Abstractions` while retaining the `SharpLink.Sdk` namespace. `SharpLink.Sdk` forwards every type published by 1.0.0, preserving existing compiled consumers without introducing a NuGet dependency cycle. + +### Changed + +- The README multi-cluster client section is now fully localized in Chinese, and the package graph, separated-contract guidance, architecture, and release order reflect the SDK-only contract reference model. +- All SharpLink NuGet packages now include the transparent SharpLink icon, which is also displayed in the README. + +### Compatibility + +- Protocol v2 bytes, generated contract IDs, runtime routing, transport behavior, and public type names are unchanged. This patch only repairs package dependency closure, preserves old assembly references through type forwarding, and updates release assets and documentation. + ## [1.0.0] - 2026-08-02 ### Highlights diff --git a/Directory.Build.props b/Directory.Build.props index 0d2c1db..7565cfc 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,11 +7,12 @@ - 1.0.0 + 1.0.1 sunsi MIT false README.md + sharplink-icon.png rpc;dotnet;source-generator;streaming;ipc;tcp;shared-memory;nativeaot https://github.com/SunSi12138/SharpLink/blob/v$(Version)/CHANGELOG.md https://github.com/SunSi12138/SharpLink @@ -46,6 +47,7 @@ + diff --git a/README.md b/README.md index 6551bac..8f3382c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # SharpLink +

+ SharpLink 图标 +

+ [![PR Quick](https://github.com/SunSi12138/SharpLink/actions/workflows/pr-quick.yml/badge.svg)](https://github.com/SunSi12138/SharpLink/actions/workflows/pr-quick.yml) [![Nightly Regression](https://github.com/SunSi12138/SharpLink/actions/workflows/nightly.yml/badge.svg)](https://github.com/SunSi12138/SharpLink/actions/workflows/nightly.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) @@ -19,9 +23,9 @@ 核心项目(`src/`): -- `SharpLink.Abstractions`:Protocol v2 公共模型、公共接口、通道与传输抽象 +- `SharpLink.Abstractions`:契约标记、Protocol v2 公共模型、公共接口、通道与传输抽象 - `SharpLink.Runtime`:`RpcSession`、`StreamManager`、实例级 Codec Provider、传输实现与底层收发逻辑 -- `SharpLink.Sdk`:`IService`、`[RpcContract]`、`[RpcService]`、`[Oneway]`、`[Timeout]` 等契约标记 +- `SharpLink.Sdk`:契约项目的单一引用入口,提供分析器、源生成器及 1.0.0 类型转发兼容层 - `SharpLink.Client`:客户端 Builder、连接生命周期、请求管理与代理调用通道 - `SharpLink.Server`:服务端 Builder、连接管理、Stub 分发、心跳与取消处理 - `SharpLink.Hosting`:`IServiceCollection` 扩展与 HostedService 集成 @@ -99,22 +103,18 @@ dotnet run --project demo/SeparatedClient/SeparatedClient.csproj [assembly: SharpLinkRpcContracts(typeof(MyContract1), typeof(MyContract2))] ``` -## Multi-cluster clients +## 多集群客户端 -`SharpLinkMultiClusterClientBuilder` owns several isolated child clients. A contract is mapped to a -single child while its proxy is created; RPC calls made through that proxy do not consult a -coordinator, cluster name, or per-call routing context. +`SharpLinkMultiClusterClientBuilder` 管理多个彼此隔离的子客户端。创建代理时,每个契约只映射到一个子客户端;之后通过该代理发起 RPC 调用时,不会再查询协调器、集群名称或逐调用路由上下文。 -Declare static contract-assembly routes in the application or host assembly, not in a reusable -contract package: +静态契约程序集路由应声明在应用或宿主程序集中,不要写入可复用的契约包: ```csharp [assembly: SharpLinkClusterContractAssembly("orders", typeof(OrderContractsMarker))] [assembly: SharpLinkClusterContractAssembly("payments", typeof(PaymentContractsMarker))] ``` -Configure each slot with the existing child builder API. The `UseCluster` method inside the delegate -still configures endpoint topology for that one slot; it is not the multi-cluster coordinator API. +每个槽位继续使用现有的子 Builder API 配置。委托内的 `UseCluster` 仍然只负责该槽位自身的端点拓扑,并不是多集群协调器 API。 ```csharp var client = SharpLinkMultiClusterClientBuilder.Create() @@ -127,18 +127,14 @@ var orders = client.Get(); var payments = client.Get(); ``` -Every slot is required by default. A slot intentionally reserved for plugins must explicitly opt in: +默认情况下,每个槽位都必须具有契约。专门预留给插件的槽位必须显式启用动态契约: ```csharp .AddCluster("plugins", child => child.UseTcp("127.0.0.1", 5103), slot => slot.AllowDynamicContracts = true) ``` -Dynamic contracts are registered against an explicit slot with -`RegisterAssembly(cluster, assembly)`, `UnregisterAssemblyAsync(cluster, assembly, timeout)`, and -`ReplaceAssemblyAsync(cluster, oldAssembly, newAssembly, timeout)`. There is no default cluster, -per-call cluster override, cross-cluster retry, or cluster identifier on the wire. See -[`doc/dynamic-modules-and-multicluster.md`](doc/dynamic-modules-and-multicluster.md) for lifecycle and migration details. +动态契约必须注册到明确指定的槽位,相关 API 为 `RegisterAssembly(cluster, assembly)`、`UnregisterAssemblyAsync(cluster, assembly, timeout)` 和 `ReplaceAssemblyAsync(cluster, oldAssembly, newAssembly, timeout)`。当前不存在默认集群、逐调用集群覆盖、跨集群重试,线上协议也不携带集群标识。生命周期与迁移细节见 [`doc/dynamic-modules-and-multicluster.md`](doc/dynamic-modules-and-multicluster.md)。 ## 契约 Manifest 与兼容性基线 diff --git a/assets/sharplink-icon.png b/assets/sharplink-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c3e97c45ee25fe01a4c3ec75e5c1358a4171e1f4 GIT binary patch literal 39137 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 SharpLink.Runtime -> SharpLink.Abstractions -SharpLink.Sdk - -> IService / RpcContract / RpcService / Oneway / Timeout / SharpLinkCallOptions +Contract project + -> SharpLink.Sdk + -> SharpLink.Runtime + -> SharpLink.Abstractions -SharpLink.Generator - -> 扫描契约与服务,生成 Proxy / Stub / Codec / Assembly Manifest +SharpLink.Sdk + -> SharpLink.Generator(Analyzer) + -> 1.0.0 契约类型转发兼容层 SharpLink.Serializer.SharpPack -> 声明通用 Codec Adapter registration,并为复杂对象图提供 manifest-scoped SharpPack Context @@ -21,6 +24,7 @@ SharpLink.Serializer.SharpPack ## 各模块职责 - `SharpLink.Abstractions` + - 保持 `SharpLink.Sdk` 命名空间的契约标记(`IService` / `RpcContract` / `RpcService` / `Oneway` / `Timeout` / `SharpLinkCallOptions`) - Protocol v2 模型(`ProtocolV2FrameType` / `ProtocolV2FrameFlags` / `ProtocolV2Constants`) - 核心抽象(`IRpcChannel`、`IRpcStub`、`IClientTransportFactory`、`IServerTransportListener`、`ITransportConnection`、`IRpcSession`、`IRpcCodec`) - 结构化错误模型(`SharpLinkException` / `SharpLinkErrorCode`) @@ -33,8 +37,10 @@ SharpLink.Serializer.SharpPack - Protocol v2 帧编解码、发送泵、池化缓冲与并发容器 - `SharpLink.Sdk` - - 只承载契约层标记和最小公共类型 - - 当前不承载 Builder;Builder 位于 `SharpLink.Client` 和 `SharpLink.Server` + - 作为契约项目的单一包引用入口,传递引入 Runtime 和 Abstractions + - 携带编译期 Analyzer 与 Source Generator + - 将 1.0.0 发布过的契约类型转发到 Abstractions,保持旧二进制引用兼容 + - 不承载 Builder;Builder 位于 `SharpLink.Client` 和 `SharpLink.Server` - `SharpLink.Client` - `SharpClientBuilder` diff --git a/doc/getting-started.md b/doc/getting-started.md index 049220e..a7b63eb 100644 --- a/doc/getting-started.md +++ b/doc/getting-started.md @@ -60,7 +60,7 @@ Client 和 Server 都是异步可释放对象。生产代码必须在停止时 ## 分离部署 -推荐把契约放在独立程序集,由 Client 和 Server 共同引用。契约程序集也必须引用 SDK、Abstractions、Runtime 和 Generator,因为生成代理、Stub 与 Manifest 依赖这些类型。完整结构见: +推荐把契约放在独立程序集,由 Client 和 Server 共同引用。契约程序集只需引用 `SharpLink.Sdk`;SDK 会传递引入生成 Proxy、Stub、Codec 与 Manifest 所需的 Runtime 和 Abstractions,并自动携带 Source Generator。Client 和 Server 项目再分别引用契约程序集及自身所需的 `SharpLink.Client` 或 `SharpLink.Server` 包。完整结构见: - `demo/SeparatedContracts` - `demo/SeparatedServer` diff --git a/doc/index.md b/doc/index.md index a77d26e..fbb1578 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,6 +1,6 @@ # SharpLink 文档 -本文档集以当前源码和 `1.0.0` 稳定版为准,不再按 0.x 小版本保存用户文档。公开 API 的精确参数、返回值和异常语义同时通过 NuGet 包内 XML 文档提供。 +本文档集以当前源码和 `1.0.1` 稳定版为准,不再按 0.x 小版本保存用户文档。公开 API 的精确参数、返回值和异常语义同时通过 NuGet 包内 XML 文档提供。 ## 学习路径 diff --git a/doc/releasing.md b/doc/releasing.md index 452e3dd..b0a970d 100644 --- a/doc/releasing.md +++ b/doc/releasing.md @@ -4,7 +4,7 @@ ## 版本与兼容性 -- NuGet 包版本由 `VersionPrefix` 和可选的 `VersionSuffix` 组成。稳定版 `1.0.0` 不设置后缀;预发布版本可使用例如 `rc7` 的后缀。 +- NuGet 包版本由 `VersionPrefix` 和可选的 `VersionSuffix` 组成。稳定版不设置后缀;预发布版本可使用例如 `rc7` 的后缀。 - `AssemblyVersion` 与 `FileVersion` 始终使用四段纯数字;预发布后缀只进入包版本和 `InformationalVersion`。 - 冻结前更新 `CHANGELOG.md`、包引用示例和迁移说明。公开 API、Protocol v2、生成代码、契约 Manifest 或默认行为的变化必须明确标注兼容性。 - `1.0.0` 发布后保留其公开 API 包作为后续 `PackageValidationBaselineVersion`;不在补丁版本中进行破坏性 API 或 wire 变更。 @@ -47,7 +47,7 @@ ## 发布与回滚 -`release-gate.yml` 只在 `v*` 标签触发、全部三平台测试/AOT/包安装/Chaos 门禁通过后进入受保护的 `release` Environment。发布 job 下载同一次运行产出的 `.nupkg` 和 `.snupkg`,使用 NuGet.org OIDC Trusted Publishing,不保存长期 API key;手工触发 Release Gate 只验证,不发布。推送前再次校验每个包的 ID、版本、SHA 和符号包配对关系,并按 `Sdk → Abstractions → Runtime/Serializer → Client/Server → Hosting` 顺序发布。 +`release-gate.yml` 只在 `v*` 标签触发、全部三平台测试/AOT/包安装/Chaos 门禁通过后进入受保护的 `release` Environment。发布 job 下载同一次运行产出的 `.nupkg` 和 `.snupkg`,使用 NuGet.org OIDC Trusted Publishing,不保存长期 API key;手工触发 Release Gate 只验证,不发布。推送前再次校验每个包的 ID、版本、SHA 和符号包配对关系,并按 `Abstractions → Runtime → Sdk/Serializer → Client/Server → Hosting` 顺序发布。 NuGet 包不可覆盖或删除来替代修复。若发布内容有缺陷: diff --git a/eng/verify-packages.sh b/eng/verify-packages.sh index 3f44620..70348d3 100755 --- a/eng/verify-packages.sh +++ b/eng/verify-packages.sh @@ -48,11 +48,20 @@ for package_id in "${PACKAGES[@]}"; do unzip -Z1 "$nupkg" | grep -Fx "lib/net10.0/$package_id.dll" >/dev/null unzip -Z1 "$nupkg" | grep -Fx "lib/net10.0/$package_id.xml" >/dev/null + unzip -Z1 "$nupkg" | grep -Fx "sharplink-icon.png" >/dev/null unzip -Z1 "$snupkg" | grep -Fx "lib/net10.0/$package_id.pdb" >/dev/null unzip -p "$nupkg" "$package_id.nuspec" | grep -F "commit=\"$EXPECTED_COMMIT\"" >/dev/null done unzip -Z1 "$ARTIFACT_DIR/SharpLink.Sdk.$EXPECTED_VERSION.nupkg" | grep -Fx "analyzers/dotnet/cs/SharpLink.Generator.dll" >/dev/null +unzip -p "$ARTIFACT_DIR/SharpLink.Sdk.$EXPECTED_VERSION.nupkg" SharpLink.Sdk.nuspec | + grep -F "/dev/null + +if unzip -p "$ARTIFACT_DIR/SharpLink.Abstractions.$EXPECTED_VERSION.nupkg" SharpLink.Abstractions.nuspec | + grep -F '/dev/null; then + echo "SharpLink.Abstractions must not depend on SharpLink.Sdk." >&2 + exit 1 +fi echo "Verified ${#PACKAGES[@]} package and symbol pairs for $EXPECTED_VERSION at $EXPECTED_COMMIT." diff --git a/src/SharpLink.Sdk/IService.cs b/src/SharpLink.Abstractions/Sdk/IService.cs similarity index 100% rename from src/SharpLink.Sdk/IService.cs rename to src/SharpLink.Abstractions/Sdk/IService.cs diff --git a/src/SharpLink.Sdk/IdempotentAttribute.cs b/src/SharpLink.Abstractions/Sdk/IdempotentAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/IdempotentAttribute.cs rename to src/SharpLink.Abstractions/Sdk/IdempotentAttribute.cs diff --git a/src/SharpLink.Sdk/NonCancellableAttribute.cs b/src/SharpLink.Abstractions/Sdk/NonCancellableAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/NonCancellableAttribute.cs rename to src/SharpLink.Abstractions/Sdk/NonCancellableAttribute.cs diff --git a/src/SharpLink.Sdk/OnewayAttribute.cs b/src/SharpLink.Abstractions/Sdk/OnewayAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/OnewayAttribute.cs rename to src/SharpLink.Abstractions/Sdk/OnewayAttribute.cs diff --git a/src/SharpLink.Sdk/RpcCodecAdapterAttribute.cs b/src/SharpLink.Abstractions/Sdk/RpcCodecAdapterAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/RpcCodecAdapterAttribute.cs rename to src/SharpLink.Abstractions/Sdk/RpcCodecAdapterAttribute.cs diff --git a/src/SharpLink.Sdk/RpcCodecAdapterRegistrationAttribute.cs b/src/SharpLink.Abstractions/Sdk/RpcCodecAdapterRegistrationAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/RpcCodecAdapterRegistrationAttribute.cs rename to src/SharpLink.Abstractions/Sdk/RpcCodecAdapterRegistrationAttribute.cs diff --git a/src/SharpLink.Sdk/RpcContractAttribute.cs b/src/SharpLink.Abstractions/Sdk/RpcContractAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/RpcContractAttribute.cs rename to src/SharpLink.Abstractions/Sdk/RpcContractAttribute.cs diff --git a/src/SharpLink.Sdk/RpcIgnoreAttribute.cs b/src/SharpLink.Abstractions/Sdk/RpcIgnoreAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/RpcIgnoreAttribute.cs rename to src/SharpLink.Abstractions/Sdk/RpcIgnoreAttribute.cs diff --git a/src/SharpLink.Sdk/RpcMemberAttribute.cs b/src/SharpLink.Abstractions/Sdk/RpcMemberAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/RpcMemberAttribute.cs rename to src/SharpLink.Abstractions/Sdk/RpcMemberAttribute.cs diff --git a/src/SharpLink.Sdk/RpcRequiredAttribute.cs b/src/SharpLink.Abstractions/Sdk/RpcRequiredAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/RpcRequiredAttribute.cs rename to src/SharpLink.Abstractions/Sdk/RpcRequiredAttribute.cs diff --git a/src/SharpLink.Sdk/RpcSerializableAttribute.cs b/src/SharpLink.Abstractions/Sdk/RpcSerializableAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/RpcSerializableAttribute.cs rename to src/SharpLink.Abstractions/Sdk/RpcSerializableAttribute.cs diff --git a/src/SharpLink.Sdk/RpcServiceAttribute.cs b/src/SharpLink.Abstractions/Sdk/RpcServiceAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/RpcServiceAttribute.cs rename to src/SharpLink.Abstractions/Sdk/RpcServiceAttribute.cs diff --git a/src/SharpLink.Sdk/RpcUnionCaseAttribute.cs b/src/SharpLink.Abstractions/Sdk/RpcUnionCaseAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/RpcUnionCaseAttribute.cs rename to src/SharpLink.Abstractions/Sdk/RpcUnionCaseAttribute.cs diff --git a/src/SharpLink.Sdk/SharpLinkCallOptions.cs b/src/SharpLink.Abstractions/Sdk/SharpLinkCallOptions.cs similarity index 100% rename from src/SharpLink.Sdk/SharpLinkCallOptions.cs rename to src/SharpLink.Abstractions/Sdk/SharpLinkCallOptions.cs diff --git a/src/SharpLink.Sdk/SharpLinkClusterContractAssemblyAttribute.cs b/src/SharpLink.Abstractions/Sdk/SharpLinkClusterContractAssemblyAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/SharpLinkClusterContractAssemblyAttribute.cs rename to src/SharpLink.Abstractions/Sdk/SharpLinkClusterContractAssemblyAttribute.cs diff --git a/src/SharpLink.Sdk/SharpLinkMetadata.cs b/src/SharpLink.Abstractions/Sdk/SharpLinkMetadata.cs similarity index 100% rename from src/SharpLink.Sdk/SharpLinkMetadata.cs rename to src/SharpLink.Abstractions/Sdk/SharpLinkMetadata.cs diff --git a/src/SharpLink.Sdk/SharpLinkRpcContractsAttribute.cs b/src/SharpLink.Abstractions/Sdk/SharpLinkRpcContractsAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/SharpLinkRpcContractsAttribute.cs rename to src/SharpLink.Abstractions/Sdk/SharpLinkRpcContractsAttribute.cs diff --git a/src/SharpLink.Sdk/SharpLinkServiceLifetime.cs b/src/SharpLink.Abstractions/Sdk/SharpLinkServiceLifetime.cs similarity index 100% rename from src/SharpLink.Sdk/SharpLinkServiceLifetime.cs rename to src/SharpLink.Abstractions/Sdk/SharpLinkServiceLifetime.cs diff --git a/src/SharpLink.Sdk/TimeoutAttribute.cs b/src/SharpLink.Abstractions/Sdk/TimeoutAttribute.cs similarity index 100% rename from src/SharpLink.Sdk/TimeoutAttribute.cs rename to src/SharpLink.Abstractions/Sdk/TimeoutAttribute.cs diff --git a/src/SharpLink.Abstractions/SharpLink.Abstractions.csproj b/src/SharpLink.Abstractions/SharpLink.Abstractions.csproj index 5e5581d..6361784 100644 --- a/src/SharpLink.Abstractions/SharpLink.Abstractions.csproj +++ b/src/SharpLink.Abstractions/SharpLink.Abstractions.csproj @@ -3,6 +3,6 @@ - + diff --git a/src/SharpLink.Sdk/SharpLink.Sdk.csproj b/src/SharpLink.Sdk/SharpLink.Sdk.csproj index 0920400..21aaca9 100644 --- a/src/SharpLink.Sdk/SharpLink.Sdk.csproj +++ b/src/SharpLink.Sdk/SharpLink.Sdk.csproj @@ -1,5 +1,6 @@ + + + + + diff --git a/test/SharpLink.SdkOnlyPackageSmoke/EchoContract.cs b/test/SharpLink.SdkOnlyPackageSmoke/EchoContract.cs new file mode 100644 index 0000000..a7d6908 --- /dev/null +++ b/test/SharpLink.SdkOnlyPackageSmoke/EchoContract.cs @@ -0,0 +1,9 @@ +using SharpLink.Sdk; + +namespace SharpLink.SdkOnlyPackageSmoke; + +[RpcContract] +public interface IEchoService : IService +{ + ValueTask EchoAsync(string value, CancellationToken cancellationToken); +} diff --git a/test/SharpLink.SdkOnlyPackageSmoke/SharpLink.SdkOnlyPackageSmoke.csproj b/test/SharpLink.SdkOnlyPackageSmoke/SharpLink.SdkOnlyPackageSmoke.csproj new file mode 100644 index 0000000..a478b1a --- /dev/null +++ b/test/SharpLink.SdkOnlyPackageSmoke/SharpLink.SdkOnlyPackageSmoke.csproj @@ -0,0 +1,14 @@ + + + net10.0 + enable + enable + false + $(VersionPrefix) + $(VersionPrefix)-$(VersionSuffix) + + + + + + diff --git a/test/SharpLink.UnitTests/SdkTypeForwardingTests.cs b/test/SharpLink.UnitTests/SdkTypeForwardingTests.cs new file mode 100644 index 0000000..921ba57 --- /dev/null +++ b/test/SharpLink.UnitTests/SdkTypeForwardingTests.cs @@ -0,0 +1,59 @@ +using System.Linq; + +namespace SharpLink.UnitTests; + +public class SdkTypeForwardingTests +{ + private static readonly string[] PublishedContractTypes = + [ + "SharpLink.Sdk.IdempotentAttribute", + "SharpLink.Sdk.IService", + "SharpLink.Sdk.NonCancellableAttribute", + "SharpLink.Sdk.OnewayAttribute", + "SharpLink.Sdk.RpcCodecAdapterAttribute", + "SharpLink.Sdk.RpcCodecAdapterRegistrationAttribute", + "SharpLink.Sdk.RpcContractAttribute", + "SharpLink.Sdk.RpcIgnoreAttribute", + "SharpLink.Sdk.RpcMemberAttribute", + "SharpLink.Sdk.RpcRequiredAttribute", + "SharpLink.Sdk.RpcSerializableAttribute", + "SharpLink.Sdk.RpcServiceAttribute", + "SharpLink.Sdk.RpcUnionCaseAttribute", + "SharpLink.Sdk.SharpLinkCallOptions", + "SharpLink.Sdk.SharpLinkClusterContractAssemblyAttribute", + "SharpLink.Sdk.SharpLinkMetadata", + "SharpLink.Sdk.SharpLinkRpcContractsAttribute", + "SharpLink.Sdk.SharpLinkServiceLifetime", + "SharpLink.Sdk.TimeoutAttribute" + ]; + + [Test] + public void SdkAssemblyShouldForwardEveryPublishedContractTypeToAbstractions() + { + var sdkAssembly = System.Reflection.Assembly.Load("SharpLink.Sdk"); + var forwardedTypes = sdkAssembly.GetForwardedTypes() + .ToDictionary(type => type.FullName!, StringComparer.Ordinal); + + Ensure(forwardedTypes.Count == PublishedContractTypes.Length, + "SDK should expose exactly the contract types published in 1.0.0 as forwarders"); + + foreach (var typeName in PublishedContractTypes) + { + if (!forwardedTypes.TryGetValue(typeName, out var forwardedType)) + { + throw new InvalidOperationException($"SDK should forward {typeName}"); + } + + Ensure(forwardedType.Assembly.GetName().Name == "SharpLink.Abstractions", + $"{typeName} should resolve from SharpLink.Abstractions"); + } + } + + private static void Ensure(bool condition, string message) + { + if (!condition) + { + throw new InvalidOperationException(message); + } + } +} diff --git a/test/SharpLink.UnitTests/SharpLink.UnitTests.csproj b/test/SharpLink.UnitTests/SharpLink.UnitTests.csproj index e153711..c0fb15f 100644 --- a/test/SharpLink.UnitTests/SharpLink.UnitTests.csproj +++ b/test/SharpLink.UnitTests/SharpLink.UnitTests.csproj @@ -8,6 +8,7 @@ + From ed5f4fda1bf3fc888c5f3ec719bf4449c190431e Mon Sep 17 00:00:00 2001 From: sunsi Date: Sun, 2 Aug 2026 13:59:41 +0800 Subject: [PATCH 11/11] release: prepare SharpLink 1.0.1 dependency refresh --- CHANGELOG.md | 4 +++- Directory.Packages.props | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40214a3..469b693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,10 +15,12 @@ - The README multi-cluster client section is now fully localized in Chinese, and the package graph, separated-contract guidance, architecture, and release order reflect the SDK-only contract reference model. - All SharpLink NuGet packages now include the transparent SharpLink icon, which is also displayed in the README. +- Runtime and build dependencies are refreshed together: Microsoft.Extensions, System.Text.Json, and System.Threading.RateLimiting move to 10.0.10, while Microsoft.CodeAnalysis.Analyzers moves to 5.6.0. The source-generator compiler API and TUnit remain pinned to their verified SDK-compatible baselines after the proposed major updates failed the release gate. +- GitHub Actions remain pinned to exact commits while moving to checkout 7.0.1, setup-dotnet 6.0.0, upload-artifact 7.0.1, and download-artifact 8.0.1. ### Compatibility -- Protocol v2 bytes, generated contract IDs, runtime routing, transport behavior, and public type names are unchanged. This patch only repairs package dependency closure, preserves old assembly references through type forwarding, and updates release assets and documentation. +- Protocol v2 bytes, generated contract IDs, runtime routing, transport behavior, and public type names are unchanged. This patch repairs package dependency closure, preserves old assembly references through type forwarding, updates release assets and documentation, and refreshes compatible build/runtime dependencies. ## [1.0.0] - 2026-08-02 diff --git a/Directory.Packages.props b/Directory.Packages.props index b8d6dc6..954e930 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -9,7 +9,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive
- + + @@ -27,6 +28,6 @@ - +