From e82718678fd3289b5cf213b87434418bbc983195 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:15:40 +0000 Subject: [PATCH 1/3] feat(stlc): configurable CI runner and private-production-repo support in workflow templates --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23c20df9..a48e4be5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: lint: timeout-minutes: 10 name: lint - runs-on: ${{ github.repository == 'stainless-sdks/imagekit-diversion-csharp' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: @@ -37,7 +37,7 @@ jobs: build: timeout-minutes: 10 name: build - runs-on: ${{ github.repository == 'stainless-sdks/imagekit-diversion-csharp' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: @@ -54,7 +54,7 @@ jobs: test: timeout-minutes: 10 name: test - runs-on: ${{ github.repository == 'stainless-sdks/imagekit-diversion-csharp' && 'depot-windows-2022' || 'windows-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-windows-2022' || 'windows-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 From 2bec549e4d11458a351838320952b6fd96a2742d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Jul 2026 13:38:04 +0000 Subject: [PATCH 2/3] fix(client): tolerate JSON null in required untyped fields and prefer more specific union variants Also corrects date-time formatting in generated URL test expectations. --- src/Imagekit.Tests/Core/JsonDictionaryTest.cs | 37 ++++++++++++++++++ .../Core/MultipartJsonDictionaryTest.cs | 38 +++++++++++++++++++ src/Imagekit/Core/JsonDictionary.cs | 16 ++++++++ src/Imagekit/Core/MultipartJsonDictionary.cs | 16 ++++++++ .../Webhooks/UnsafeUnwrapWebhookEvent.cs | 22 +++++------ .../Models/Webhooks/UnwrapWebhookEvent.cs | 22 +++++------ 6 files changed, 129 insertions(+), 22 deletions(-) diff --git a/src/Imagekit.Tests/Core/JsonDictionaryTest.cs b/src/Imagekit.Tests/Core/JsonDictionaryTest.cs index ad185457..786f1096 100644 --- a/src/Imagekit.Tests/Core/JsonDictionaryTest.cs +++ b/src/Imagekit.Tests/Core/JsonDictionaryTest.cs @@ -206,6 +206,43 @@ public void GetNotNullStruct_ThrowsWhenTypeInvalid() Assert.Contains("'text' must be of type", exception.Message); } + [Fact] + public void GetNotAbsentElement_ReturnsValue() + { + var dict = new JsonDictionary(); + dict.Set("age", 30); + + var age = dict.GetNotAbsentElement("age"); + + Assert.Equal(30, age.GetInt32()); + } + + [Fact] + public void GetNotAbsentElement_ThrowsWhenKeyAbsent() + { + var dict = new JsonDictionary(); + + var exception = Assert.Throws(() => + dict.GetNotAbsentElement("missing") + ); + Assert.Contains("'missing' cannot be absent", exception.Message); + } + + [Fact] + public void GetNotAbsentElement_ReturnsNullElementWhenValueIsNull() + { + var dict = new JsonDictionary( + new Dictionary + { + ["nullable"] = JsonSerializer.SerializeToElement(null), + } + ); + + var element = dict.GetNotAbsentElement("nullable"); + + Assert.Equal(JsonValueKind.Null, element.ValueKind); + } + [Fact] public void GetNullableClass_ReturnsValueWhenPresent() { diff --git a/src/Imagekit.Tests/Core/MultipartJsonDictionaryTest.cs b/src/Imagekit.Tests/Core/MultipartJsonDictionaryTest.cs index 705ca35f..d92ed7ab 100644 --- a/src/Imagekit.Tests/Core/MultipartJsonDictionaryTest.cs +++ b/src/Imagekit.Tests/Core/MultipartJsonDictionaryTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Frozen; using System.Collections.Generic; +using System.Text.Json; using Imagekit.Core; using Imagekit.Exceptions; @@ -205,6 +206,43 @@ public void GetNotNullStruct_ThrowsWhenTypeInvalid() Assert.Contains("'text' must be of type", exception.Message); } + [Fact] + public void GetNotAbsentElement_ReturnsValue() + { + var dict = new MultipartJsonDictionary(); + dict.Set("age", 30); + + var age = dict.GetNotAbsentElement("age"); + + Assert.Equal(30, age.GetInt32()); + } + + [Fact] + public void GetNotAbsentElement_ThrowsWhenKeyAbsent() + { + var dict = new MultipartJsonDictionary(); + + var exception = Assert.Throws(() => + dict.GetNotAbsentElement("missing") + ); + Assert.Contains("'missing' cannot be absent", exception.Message); + } + + [Fact] + public void GetNotAbsentElement_ReturnsNullElementWhenValueIsNull() + { + var dict = new MultipartJsonDictionary( + new Dictionary + { + ["nullable"] = MultipartJsonSerializer.SerializeToElement(null), + } + ); + + var element = dict.GetNotAbsentElement("nullable"); + + Assert.Equal(JsonValueKind.Null, element.ValueKind); + } + [Fact] public void GetNullableClass_ReturnsValueWhenPresent() { diff --git a/src/Imagekit/Core/JsonDictionary.cs b/src/Imagekit/Core/JsonDictionary.cs index 6074a2bd..bfd153de 100644 --- a/src/Imagekit/Core/JsonDictionary.cs +++ b/src/Imagekit/Core/JsonDictionary.cs @@ -149,6 +149,22 @@ public T GetNotNullStruct(string key) return deserialized; } + /// + /// Gets the raw JSON element for a key that must be present, without rejecting JSON null. + /// + /// Used for values of unknown type, which can be any JSON value including null. A JSON + /// null is returned as a whose ValueKind is + /// Null. + /// + public JsonElement GetNotAbsentElement(string key) + { + if (!_rawData.TryGetValue(key, out JsonElement element)) + { + throw new ImageKitInvalidDataException($"'{key}' cannot be absent"); + } + return element; + } + public override string ToString() => JsonSerializer.Serialize( FriendlyJsonPrinter.PrintValue(this._rawData), diff --git a/src/Imagekit/Core/MultipartJsonDictionary.cs b/src/Imagekit/Core/MultipartJsonDictionary.cs index 296cc16d..97b89ddd 100644 --- a/src/Imagekit/Core/MultipartJsonDictionary.cs +++ b/src/Imagekit/Core/MultipartJsonDictionary.cs @@ -152,6 +152,22 @@ public T GetNotNullStruct(string key) return deserialized; } + /// + /// Gets the raw JSON element for a key that must be present, without rejecting JSON null. + /// + /// Used for values of unknown type, which can be any JSON value including null. A JSON + /// null is returned as a whose ValueKind is + /// Null. + /// + public JsonElement GetNotAbsentElement(string key) + { + if (!_rawData.TryGetValue(key, out MultipartJsonElement element)) + { + throw new ImageKitInvalidDataException($"'{key}' cannot be absent"); + } + return element.Json; + } + public override string ToString() => JsonSerializer.Serialize( FriendlyJsonPrinter.PrintValue(this._rawData), diff --git a/src/Imagekit/Models/Webhooks/UnsafeUnwrapWebhookEvent.cs b/src/Imagekit/Models/Webhooks/UnsafeUnwrapWebhookEvent.cs index 3f4c49b9..661fe574 100644 --- a/src/Imagekit/Models/Webhooks/UnsafeUnwrapWebhookEvent.cs +++ b/src/Imagekit/Models/Webhooks/UnsafeUnwrapWebhookEvent.cs @@ -742,7 +742,7 @@ JsonSerializerOptions options { try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -760,7 +760,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -778,7 +778,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -796,7 +796,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -814,7 +814,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -850,7 +850,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -868,7 +868,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -886,7 +886,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -904,7 +904,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -922,7 +922,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -940,7 +940,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); diff --git a/src/Imagekit/Models/Webhooks/UnwrapWebhookEvent.cs b/src/Imagekit/Models/Webhooks/UnwrapWebhookEvent.cs index d39b6671..8c71429f 100644 --- a/src/Imagekit/Models/Webhooks/UnwrapWebhookEvent.cs +++ b/src/Imagekit/Models/Webhooks/UnwrapWebhookEvent.cs @@ -719,7 +719,7 @@ JsonSerializerOptions options { try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -737,7 +737,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -755,7 +755,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -773,7 +773,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -791,7 +791,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -827,7 +827,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -845,7 +845,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -863,7 +863,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -881,7 +881,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -899,7 +899,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); @@ -917,7 +917,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, options ); From 265ab207ce4c7d30a820ed540c0422834f05583e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Jul 2026 13:38:32 +0000 Subject: [PATCH 3/3] release: 6.3.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ src/Imagekit/Imagekit.csproj | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5709eb5d..e704c06d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "6.2.0" + ".": "6.3.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 251685c9..35828d2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 6.3.0 (2026-07-24) + +Full Changelog: [v6.2.0...v6.3.0](https://github.com/imagekit-developer/imagekit-dotnet/compare/v6.2.0...v6.3.0) + +### Features + +* **stlc:** configurable CI runner and private-production-repo support in workflow templates ([e827186](https://github.com/imagekit-developer/imagekit-dotnet/commit/e82718678fd3289b5cf213b87434418bbc983195)) + + +### Bug Fixes + +* **client:** tolerate JSON null in required untyped fields and prefer more specific union variants ([2bec549](https://github.com/imagekit-developer/imagekit-dotnet/commit/2bec549e4d11458a351838320952b6fd96a2742d)) + ## 6.2.0 (2026-07-14) Full Changelog: [v6.1.0...v6.2.0](https://github.com/imagekit-developer/imagekit-dotnet/compare/v6.1.0...v6.2.0) diff --git a/src/Imagekit/Imagekit.csproj b/src/Imagekit/Imagekit.csproj index e3a0a2c9..872c7cd3 100644 --- a/src/Imagekit/Imagekit.csproj +++ b/src/Imagekit/Imagekit.csproj @@ -3,7 +3,7 @@ Image Kit C# Imagekit - 6.2.0 + 6.3.0 The official .NET library for the Image Kit API. Library README.md