From 9fcde9d5cee487782d8e9cf3914a032e99ffb8d6 Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Mon, 23 Feb 2026 09:41:36 +0100 Subject: [PATCH 01/18] C# CI --- .github/workflows/uniffi.yaml | 56 ++++++++++++++++++ bindings/uniffi/.gitignore | 2 + .../csharp/GoRules/ZenEngine/JsonBuffer.cs | 23 ++++++++ .../uniffi/nuget/GoRules.ZenEngine.csproj | 58 +++++++++++++++++++ .../uniffi/scripts/fix-csharp-bindings.sh | 38 ++++++++++++ 5 files changed, 177 insertions(+) create mode 100644 bindings/uniffi/lib/csharp/GoRules/ZenEngine/JsonBuffer.cs create mode 100644 bindings/uniffi/nuget/GoRules.ZenEngine.csproj create mode 100755 bindings/uniffi/scripts/fix-csharp-bindings.sh diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index b4193941..fa231c2b 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -137,6 +137,62 @@ jobs: run: ./gradlew publishMavenKotlinPublicationToCentralPortal publishMavenJavaPublicationToCentralPortal + release-csharp: + runs-on: ubuntu-latest + needs: [ build ] + if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi')" + defaults: + run: + working-directory: ${{ env.UNIFFI_DIRECTORY }} + + steps: + - uses: actions/checkout@v3 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + + - name: Setup Rust Toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: build/generated/resources + + - name: Move artifacts + run: mv ../../build ./ + + - name: Install uniffi-bindgen-cs + run: cargo install uniffi-bindgen-cs --git https://github.com/aspect-build/uniffi-bindgen-cs --tag v0.10.0+v0.29.4 + + - name: Generate C# bindings + run: | + uniffi-bindgen-cs \ + --library build/generated/resources/darwin-x86-64/libzen_uniffi.dylib \ + --out-dir build/generated/csharp + + - name: Fix async callback interfaces + run: bash scripts/fix-csharp-bindings.sh build/generated/csharp/zen_uniffi.cs + + - name: Extract version from Cargo.toml + id: version + run: | + VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "Detected version: $VERSION" + + - name: Pack NuGet package + run: dotnet pack nuget/GoRules.ZenEngine.csproj -c Release -p:Version=$VERSION + + - name: Push to NuGet.org + run: | + dotnet nuget push nuget/bin/Release/*.nupkg \ + --api-key ${{ secrets.NUGET_API_KEY }} \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate + build-ios: if: "!contains(github.event.head_commit.message, 'skip ci')" env: diff --git a/bindings/uniffi/.gitignore b/bindings/uniffi/.gitignore index 6eb8b6a7..dd20902a 100644 --- a/bindings/uniffi/.gitignore +++ b/bindings/uniffi/.gitignore @@ -1,3 +1,5 @@ .idea .gradle build/ +build-android/ +jniLibs/ \ No newline at end of file diff --git a/bindings/uniffi/lib/csharp/GoRules/ZenEngine/JsonBuffer.cs b/bindings/uniffi/lib/csharp/GoRules/ZenEngine/JsonBuffer.cs new file mode 100644 index 00000000..d63fc8d6 --- /dev/null +++ b/bindings/uniffi/lib/csharp/GoRules/ZenEngine/JsonBuffer.cs @@ -0,0 +1,23 @@ +namespace GoRules.ZenEngine; + +using System.Text; + +public class JsonBuffer +{ + public byte[] Value { get; } + + public JsonBuffer(byte[] value) + { + Value = value; + } + + public JsonBuffer(string json) + { + Value = Encoding.UTF8.GetBytes(json); + } + + public override string ToString() + { + return Encoding.UTF8.GetString(Value); + } +} diff --git a/bindings/uniffi/nuget/GoRules.ZenEngine.csproj b/bindings/uniffi/nuget/GoRules.ZenEngine.csproj new file mode 100644 index 00000000..3c9b0d27 --- /dev/null +++ b/bindings/uniffi/nuget/GoRules.ZenEngine.csproj @@ -0,0 +1,58 @@ + + + + net8.0 + GoRules.ZenEngine + GoRules + ZEN Engine - Business Rules Engine for .NET. Execute JSON Decision Models (JDM) with native performance via Rust FFI bindings. + MIT + https://github.com/gorules/zen + https://github.com/gorules/zen + rules-engine;business-rules;decision-engine;jdm;gorules + enable + enable + true + true + $(NoWarn);CS1591 + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/uniffi/scripts/fix-csharp-bindings.sh b/bindings/uniffi/scripts/fix-csharp-bindings.sh new file mode 100755 index 00000000..fd164418 --- /dev/null +++ b/bindings/uniffi/scripts/fix-csharp-bindings.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# +# fix-csharp-bindings.sh +# +# Fixes the async callback interface bug in C# bindings generated by uniffi-bindgen-cs. +# +# The generator produces sync interface methods (returning T directly) but the +# calling code uses await + .WaitAsync(), causing compilation errors. This script +# patches the interface method signatures to return Task instead. +# +# Usage: ./fix-csharp-bindings.sh + +set -euo pipefail + +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +FILE="$1" + +if [ ! -f "$FILE" ]; then + echo "Error: File not found: $FILE" + exit 1 +fi + +echo "Fixing async callback interfaces in $FILE..." + +# Fix ZenCustomNodeCallback.Handle: sync → async (Task<>) +sed -i.bak 's/ZenEngineHandlerResponse Handle(ZenEngineHandlerRequest @key)/Task Handle(ZenEngineHandlerRequest @key)/' "$FILE" + +# Fix ZenDecisionLoaderCallback.Load: sync → async (Task<>) +sed -i.bak 's/JsonBuffer? Load(string @key)/Task Load(string @key)/' "$FILE" + +# Clean up backup file +rm -f "${FILE}.bak" + +echo "Done. Fixed async interfaces in $FILE" From eecd5c2041c0a6c20f0d927024f4c72b1ba12dfa Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Mon, 23 Feb 2026 10:19:55 +0100 Subject: [PATCH 02/18] testing with dispatch --- .github/workflows/uniffi.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index fa231c2b..4e40bcc7 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -3,6 +3,7 @@ env: UNIFFI_DIRECTORY: bindings/uniffi on: + workflow_dispatch: push: branches: - master @@ -79,7 +80,7 @@ jobs: release-java-kotlin: runs-on: ubuntu-latest needs: [ build ] - if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi')" + if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi') && github.event_name != 'workflow_dispatch'" defaults: run: working-directory: ${{ env.UNIFFI_DIRECTORY }} @@ -140,7 +141,7 @@ jobs: release-csharp: runs-on: ubuntu-latest needs: [ build ] - if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi')" + if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi') || github.event_name == 'workflow_dispatch'" defaults: run: working-directory: ${{ env.UNIFFI_DIRECTORY }} @@ -187,6 +188,7 @@ jobs: run: dotnet pack nuget/GoRules.ZenEngine.csproj -c Release -p:Version=$VERSION - name: Push to NuGet.org + if: "github.event_name != 'workflow_dispatch'" run: | dotnet nuget push nuget/bin/Release/*.nupkg \ --api-key ${{ secrets.NUGET_API_KEY }} \ @@ -194,7 +196,7 @@ jobs: --skip-duplicate build-ios: - if: "!contains(github.event.head_commit.message, 'skip ci')" + if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" env: OUTPUT_NAME: zen_uniffi IPHONEOS_DEPLOYMENT_TARGET: '16.0' @@ -408,7 +410,7 @@ jobs: --base "master" build-android: - if: "!contains(github.event.head_commit.message, 'skip ci')" + if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" runs-on: ubuntu-latest env: OUTPUT_NAME: zen_uniffi @@ -455,7 +457,7 @@ jobs: prepare-android-bindings: runs-on: ubuntu-latest needs: [ build ] - if: "!contains(github.event.head_commit.message, 'skip ci')" + if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" defaults: run: From fc3ecaede7d0f62ca0cafc8b7ea7ebee65b12e11 Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Mon, 23 Feb 2026 11:04:25 +0100 Subject: [PATCH 03/18] upload nuget artifact --- .github/workflows/uniffi.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index 4e40bcc7..9c30fff8 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -187,6 +187,13 @@ jobs: - name: Pack NuGet package run: dotnet pack nuget/GoRules.ZenEngine.csproj -c Release -p:Version=$VERSION + - name: Upload NuGet package artifact + uses: actions/upload-artifact@v4 + with: + name: nuget-package + path: ${{ env.UNIFFI_DIRECTORY }}/nuget/bin/Release/*.nupkg + if-no-files-found: error + - name: Push to NuGet.org if: "github.event_name != 'workflow_dispatch'" run: | From 81d5c8f2cbde9e19a263e1fffedbf0d920ecc69c Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Mon, 23 Feb 2026 11:11:48 +0100 Subject: [PATCH 04/18] fixed cs-bindgen url --- .github/workflows/uniffi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index 9c30fff8..e4ecbc50 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -166,7 +166,7 @@ jobs: run: mv ../../build ./ - name: Install uniffi-bindgen-cs - run: cargo install uniffi-bindgen-cs --git https://github.com/aspect-build/uniffi-bindgen-cs --tag v0.10.0+v0.29.4 + run: cargo install uniffi-bindgen-cs --git https://github.com/NordSecurity/uniffi-bindgen-cs --tag v0.10.0+v0.29.4 - name: Generate C# bindings run: | From ed6ffb2832949e118ebb716e9aa28e2808277925 Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Mon, 23 Feb 2026 11:39:47 +0100 Subject: [PATCH 05/18] access modifier --- bindings/uniffi/uniffi.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/uniffi/uniffi.toml b/bindings/uniffi/uniffi.toml index ed2a9997..d48edaa2 100644 --- a/bindings/uniffi/uniffi.toml +++ b/bindings/uniffi/uniffi.toml @@ -20,6 +20,7 @@ from_custom = "{}" [bindings.csharp] namespace = "GoRules.ZenEngine" cdylib_name = "Libs/zen_uniffi" +access_modifier = "public" [bindings.csharp.custom_types.JsonBuffer] into_custom = "new JsonBuffer({})" From af102de5ba011065bcb29070d6f00b65d66d19b4 Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Mon, 23 Feb 2026 12:53:30 +0100 Subject: [PATCH 06/18] config fix --- .github/workflows/uniffi.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index e4ecbc50..083dc620 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -172,11 +172,19 @@ jobs: run: | uniffi-bindgen-cs \ --library build/generated/resources/darwin-x86-64/libzen_uniffi.dylib \ + --config uniffi.toml \ --out-dir build/generated/csharp - name: Fix async callback interfaces run: bash scripts/fix-csharp-bindings.sh build/generated/csharp/zen_uniffi.cs + - name: Upload generated C# source + uses: actions/upload-artifact@v4 + with: + name: csharp-generated-source + path: ${{ env.UNIFFI_DIRECTORY }}/build/generated/csharp/zen_uniffi.cs + if-no-files-found: error + - name: Extract version from Cargo.toml id: version run: | From 76647d275aef554800933f287a5c023abb80b327 Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Mon, 23 Feb 2026 13:40:08 +0100 Subject: [PATCH 07/18] cdylib_name fix --- bindings/uniffi/uniffi.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/uniffi/uniffi.toml b/bindings/uniffi/uniffi.toml index d48edaa2..c030c133 100644 --- a/bindings/uniffi/uniffi.toml +++ b/bindings/uniffi/uniffi.toml @@ -19,7 +19,7 @@ from_custom = "{}" # C# [bindings.csharp] namespace = "GoRules.ZenEngine" -cdylib_name = "Libs/zen_uniffi" +cdylib_name = "zen_uniffi" access_modifier = "public" [bindings.csharp.custom_types.JsonBuffer] From 2ec9961df3e0fe5435be0b18243951e1ec9159cc Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Tue, 24 Feb 2026 11:07:37 +0100 Subject: [PATCH 08/18] point to forked cs-bindings --- .github/workflows/uniffi.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index 083dc620..bab113fb 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -166,7 +166,7 @@ jobs: run: mv ../../build ./ - name: Install uniffi-bindgen-cs - run: cargo install uniffi-bindgen-cs --git https://github.com/NordSecurity/uniffi-bindgen-cs --tag v0.10.0+v0.29.4 + run: cargo install uniffi-bindgen-cs --git https://github.com/bcrevar-gorules/uniffi-bindgen-cs --branch fix/async-callback-interface-return-type - name: Generate C# bindings run: | @@ -175,8 +175,8 @@ jobs: --config uniffi.toml \ --out-dir build/generated/csharp - - name: Fix async callback interfaces - run: bash scripts/fix-csharp-bindings.sh build/generated/csharp/zen_uniffi.cs +# - name: Fix async callback interfaces +# run: bash scripts/fix-csharp-bindings.sh build/generated/csharp/zen_uniffi.cs - name: Upload generated C# source uses: actions/upload-artifact@v4 From fa85ac8d1adad59a82dcc915b4e844abec1591da Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Tue, 24 Feb 2026 11:34:51 +0100 Subject: [PATCH 09/18] revert workflow_dispatch, fork used for async generation cs bindings issue --- .github/workflows/uniffi.yaml | 27 ++++++------- .../uniffi/scripts/fix-csharp-bindings.sh | 38 ------------------- 2 files changed, 11 insertions(+), 54 deletions(-) delete mode 100755 bindings/uniffi/scripts/fix-csharp-bindings.sh diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index bab113fb..1077119b 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -3,7 +3,6 @@ env: UNIFFI_DIRECTORY: bindings/uniffi on: - workflow_dispatch: push: branches: - master @@ -80,7 +79,7 @@ jobs: release-java-kotlin: runs-on: ubuntu-latest needs: [ build ] - if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi') && github.event_name != 'workflow_dispatch'" + if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi')" defaults: run: working-directory: ${{ env.UNIFFI_DIRECTORY }} @@ -141,7 +140,7 @@ jobs: release-csharp: runs-on: ubuntu-latest needs: [ build ] - if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi') || github.event_name == 'workflow_dispatch'" + if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi')" defaults: run: working-directory: ${{ env.UNIFFI_DIRECTORY }} @@ -175,9 +174,6 @@ jobs: --config uniffi.toml \ --out-dir build/generated/csharp -# - name: Fix async callback interfaces -# run: bash scripts/fix-csharp-bindings.sh build/generated/csharp/zen_uniffi.cs - - name: Upload generated C# source uses: actions/upload-artifact@v4 with: @@ -202,16 +198,15 @@ jobs: path: ${{ env.UNIFFI_DIRECTORY }}/nuget/bin/Release/*.nupkg if-no-files-found: error - - name: Push to NuGet.org - if: "github.event_name != 'workflow_dispatch'" - run: | - dotnet nuget push nuget/bin/Release/*.nupkg \ - --api-key ${{ secrets.NUGET_API_KEY }} \ - --source https://api.nuget.org/v3/index.json \ - --skip-duplicate +# - name: Push to NuGet.org +# run: | +# dotnet nuget push nuget/bin/Release/*.nupkg \ +# --api-key ${{ secrets.NUGET_API_KEY }} \ +# --source https://api.nuget.org/v3/index.json \ +# --skip-duplicate build-ios: - if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" + if: "!contains(github.event.head_commit.message, 'skip ci')" env: OUTPUT_NAME: zen_uniffi IPHONEOS_DEPLOYMENT_TARGET: '16.0' @@ -425,7 +420,7 @@ jobs: --base "master" build-android: - if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" + if: "!contains(github.event.head_commit.message, 'skip ci')" runs-on: ubuntu-latest env: OUTPUT_NAME: zen_uniffi @@ -472,7 +467,7 @@ jobs: prepare-android-bindings: runs-on: ubuntu-latest needs: [ build ] - if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" + if: "!contains(github.event.head_commit.message, 'skip ci')" defaults: run: diff --git a/bindings/uniffi/scripts/fix-csharp-bindings.sh b/bindings/uniffi/scripts/fix-csharp-bindings.sh deleted file mode 100755 index fd164418..00000000 --- a/bindings/uniffi/scripts/fix-csharp-bindings.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -# -# fix-csharp-bindings.sh -# -# Fixes the async callback interface bug in C# bindings generated by uniffi-bindgen-cs. -# -# The generator produces sync interface methods (returning T directly) but the -# calling code uses await + .WaitAsync(), causing compilation errors. This script -# patches the interface method signatures to return Task instead. -# -# Usage: ./fix-csharp-bindings.sh - -set -euo pipefail - -if [ $# -ne 1 ]; then - echo "Usage: $0 " - exit 1 -fi - -FILE="$1" - -if [ ! -f "$FILE" ]; then - echo "Error: File not found: $FILE" - exit 1 -fi - -echo "Fixing async callback interfaces in $FILE..." - -# Fix ZenCustomNodeCallback.Handle: sync → async (Task<>) -sed -i.bak 's/ZenEngineHandlerResponse Handle(ZenEngineHandlerRequest @key)/Task Handle(ZenEngineHandlerRequest @key)/' "$FILE" - -# Fix ZenDecisionLoaderCallback.Load: sync → async (Task<>) -sed -i.bak 's/JsonBuffer? Load(string @key)/Task Load(string @key)/' "$FILE" - -# Clean up backup file -rm -f "${FILE}.bak" - -echo "Done. Fixed async interfaces in $FILE" From 245d0d5534bf9a6c12cf985fba8a3fffbffa225a Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Tue, 24 Feb 2026 16:07:38 +0100 Subject: [PATCH 10/18] uncomment NuGet publish --- .github/workflows/uniffi.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index 1077119b..7847093c 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -198,12 +198,12 @@ jobs: path: ${{ env.UNIFFI_DIRECTORY }}/nuget/bin/Release/*.nupkg if-no-files-found: error -# - name: Push to NuGet.org -# run: | -# dotnet nuget push nuget/bin/Release/*.nupkg \ -# --api-key ${{ secrets.NUGET_API_KEY }} \ -# --source https://api.nuget.org/v3/index.json \ -# --skip-duplicate + - name: Push to NuGet.org + run: | + dotnet nuget push nuget/bin/Release/*.nupkg \ + --api-key ${{ secrets.NUGET_API_KEY }} \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate build-ios: if: "!contains(github.event.head_commit.message, 'skip ci')" From 65743dec5d1436aefc85082c1ffb45ff27cf6f6a Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Tue, 24 Feb 2026 16:10:27 +0100 Subject: [PATCH 11/18] testing NuGet publish --- .github/workflows/uniffi.yaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index 7847093c..a75d4050 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -3,6 +3,7 @@ env: UNIFFI_DIRECTORY: bindings/uniffi on: + workflow_dispatch: push: branches: - master @@ -79,7 +80,7 @@ jobs: release-java-kotlin: runs-on: ubuntu-latest needs: [ build ] - if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi')" + if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi') && github.event_name != 'workflow_dispatch'" defaults: run: working-directory: ${{ env.UNIFFI_DIRECTORY }} @@ -140,7 +141,7 @@ jobs: release-csharp: runs-on: ubuntu-latest needs: [ build ] - if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi')" + if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi') || github.event_name == 'workflow_dispatch'" defaults: run: working-directory: ${{ env.UNIFFI_DIRECTORY }} @@ -206,7 +207,7 @@ jobs: --skip-duplicate build-ios: - if: "!contains(github.event.head_commit.message, 'skip ci')" + if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" env: OUTPUT_NAME: zen_uniffi IPHONEOS_DEPLOYMENT_TARGET: '16.0' @@ -420,7 +421,7 @@ jobs: --base "master" build-android: - if: "!contains(github.event.head_commit.message, 'skip ci')" + if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" runs-on: ubuntu-latest env: OUTPUT_NAME: zen_uniffi @@ -467,7 +468,7 @@ jobs: prepare-android-bindings: runs-on: ubuntu-latest needs: [ build ] - if: "!contains(github.event.head_commit.message, 'skip ci')" + if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" defaults: run: From 5aaeb177e14419744ca3a763f9b70e4a29eb5791 Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Wed, 25 Feb 2026 11:19:54 +0100 Subject: [PATCH 12/18] readme --- .../uniffi/nuget/GoRules.ZenEngine.csproj | 5 + bindings/uniffi/nuget/README.md | 96 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 bindings/uniffi/nuget/README.md diff --git a/bindings/uniffi/nuget/GoRules.ZenEngine.csproj b/bindings/uniffi/nuget/GoRules.ZenEngine.csproj index 3c9b0d27..5c7be94f 100644 --- a/bindings/uniffi/nuget/GoRules.ZenEngine.csproj +++ b/bindings/uniffi/nuget/GoRules.ZenEngine.csproj @@ -14,8 +14,13 @@ true true $(NoWarn);CS1591 + README.md + + + + diff --git a/bindings/uniffi/nuget/README.md b/bindings/uniffi/nuget/README.md new file mode 100644 index 00000000..1440bb75 --- /dev/null +++ b/bindings/uniffi/nuget/README.md @@ -0,0 +1,96 @@ +# GoRules.ZenEngine + +Open-source Business Rules Engine for .NET. Execute JSON Decision Models (JDM) with native performance powered by Rust. + +## Installation + +```bash +dotnet add package GoRules.ZenEngine +``` + +## Quick Start + +```csharp +using GoRules.ZenEngine; + +// Implement a loader to resolve decision files +class FileLoader : ZenDecisionLoaderCallback +{ + public Task Load(string key) + { + var bytes = File.ReadAllBytes(key); + return Task.FromResult(new JsonBuffer(bytes)); + } +} + +// Create engine and evaluate +var engine = new ZenEngine(loader: new FileLoader(), customNode: null); +var context = new JsonBuffer("{\"input\": 42}"); +var response = await engine.Evaluate("my-decision.json", context, null); +Console.WriteLine(response.result.ToString()); +``` + +## Features + +- **Decision Tables** - Rule tables with first/collect hit policies +- **Expression Language** - Built-in ZEN expression language with functions like `sum()`, `filter()`, `map()` +- **Custom Nodes** - Extend the engine with custom node handlers +- **Tracing** - Full execution trace for debugging and auditing +- **Cross-platform** - Native libraries for Windows (x64), macOS (x64/ARM), Linux (x64/ARM) + +## Tracing + +Enable tracing to inspect the execution of each node: + +```csharp +var options = new ZenEvaluateOptions(maxDepth: null, trace: true); +var response = await engine.Evaluate("decision.json", context, options); + +foreach (var (nodeId, trace) in response.trace!) +{ + Console.WriteLine($"{trace.name}: {trace.output}"); +} +``` + +## Expression Evaluation + +Evaluate expressions directly without a decision file: + +```csharp +// One-off evaluation +var result = ZenUniffiMethods.EvaluateExpression( + "sum(items) * multiplier", + new JsonBuffer("{\"items\": [10, 20, 30], \"multiplier\": 2}") +); + +// Compiled expression (reusable, better performance) +var expr = ZenExpression.Compile("a + b * 2"); +var output = expr.Evaluate(new JsonBuffer("{\"a\": 1, \"b\": 10}")); +expr.Dispose(); +``` + +## Custom Nodes + +Extend the engine with custom logic: + +```csharp +class MyCustomNode : ZenCustomNodeCallback +{ + public Task Handle(ZenEngineHandlerRequest request) + { + var output = new JsonBuffer("{\"result\": \"custom\"}"); + return Task.FromResult(new ZenEngineHandlerResponse( + output: output, + traceData: null + )); + } +} + +var engine = new ZenEngine(loader: new FileLoader(), customNode: new MyCustomNode()); +``` + +## Links + +- [GitHub Repository](https://github.com/gorules/zen) +- [GoRules Documentation](https://gorules.io/docs) +- [JDM Editor](https://editor.gorules.io) From b886d972f62c494228a8077b727d001f592c85cb Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Wed, 25 Feb 2026 13:01:49 +0100 Subject: [PATCH 13/18] trusted publishing --- .github/workflows/uniffi.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index a75d4050..93c59a71 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -141,6 +141,8 @@ jobs: release-csharp: runs-on: ubuntu-latest needs: [ build ] + permissions: + id-token: write # Required for OIDC if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi') || github.event_name == 'workflow_dispatch'" defaults: run: @@ -199,10 +201,14 @@ jobs: path: ${{ env.UNIFFI_DIRECTORY }}/nuget/bin/Release/*.nupkg if-no-files-found: error + - name: Login to NuGet + uses: nuget/setup-nuget@v2 + with: + nuget-api-key-source: trusted-publishing + - name: Push to NuGet.org run: | dotnet nuget push nuget/bin/Release/*.nupkg \ - --api-key ${{ secrets.NUGET_API_KEY }} \ --source https://api.nuget.org/v3/index.json \ --skip-duplicate From 74ba5d455b869c21de662726e6a08bedaa2648bf Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Wed, 25 Feb 2026 14:15:47 +0100 Subject: [PATCH 14/18] trusted publishing 2 --- .github/workflows/uniffi.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index 93c59a71..16e35424 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -201,14 +201,16 @@ jobs: path: ${{ env.UNIFFI_DIRECTORY }}/nuget/bin/Release/*.nupkg if-no-files-found: error - - name: Login to NuGet - uses: nuget/setup-nuget@v2 + - name: NuGet login (trusted publishing) + uses: NuGet/login@v1 + id: nuget-login with: - nuget-api-key-source: trusted-publishing + user: ${{ secrets.NUGET_USER }} - name: Push to NuGet.org run: | dotnet nuget push nuget/bin/Release/*.nupkg \ + --api-key ${{ steps.nuget-login.outputs.NUGET_API_KEY }} \ --source https://api.nuget.org/v3/index.json \ --skip-duplicate From 7ee6ca1a52c8c46945e7a3909e2bfbfa815ae59c Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Wed, 25 Feb 2026 16:29:38 +0100 Subject: [PATCH 15/18] icon and docs link --- bindings/uniffi/nuget/GoRules.ZenEngine.csproj | 3 +++ bindings/uniffi/nuget/README.md | 15 ++++++++------- bindings/uniffi/nuget/icon.png | Bin 0 -> 8564 bytes 3 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 bindings/uniffi/nuget/icon.png diff --git a/bindings/uniffi/nuget/GoRules.ZenEngine.csproj b/bindings/uniffi/nuget/GoRules.ZenEngine.csproj index 5c7be94f..9698645c 100644 --- a/bindings/uniffi/nuget/GoRules.ZenEngine.csproj +++ b/bindings/uniffi/nuget/GoRules.ZenEngine.csproj @@ -4,9 +4,11 @@ net8.0 GoRules.ZenEngine GoRules + GoRules ZEN Engine - Business Rules Engine for .NET. Execute JSON Decision Models (JDM) with native performance via Rust FFI bindings. MIT https://github.com/gorules/zen + icon.png https://github.com/gorules/zen rules-engine;business-rules;decision-engine;jdm;gorules enable @@ -19,6 +21,7 @@ + diff --git a/bindings/uniffi/nuget/README.md b/bindings/uniffi/nuget/README.md index 1440bb75..2fd72fd9 100644 --- a/bindings/uniffi/nuget/README.md +++ b/bindings/uniffi/nuget/README.md @@ -13,6 +13,12 @@ dotnet add package GoRules.ZenEngine ```csharp using GoRules.ZenEngine; +// Create engine and evaluate +var engine = new ZenEngine(loader: new FileLoader(), customNode: null); +var context = new JsonBuffer("{\"input\": 42}"); +var response = await engine.Evaluate("my-decision.json", context, null); +Console.WriteLine(response.result.ToString()); + // Implement a loader to resolve decision files class FileLoader : ZenDecisionLoaderCallback { @@ -22,12 +28,6 @@ class FileLoader : ZenDecisionLoaderCallback return Task.FromResult(new JsonBuffer(bytes)); } } - -// Create engine and evaluate -var engine = new ZenEngine(loader: new FileLoader(), customNode: null); -var context = new JsonBuffer("{\"input\": 42}"); -var response = await engine.Evaluate("my-decision.json", context, null); -Console.WriteLine(response.result.ToString()); ``` ## Features @@ -66,6 +66,7 @@ var result = ZenUniffiMethods.EvaluateExpression( // Compiled expression (reusable, better performance) var expr = ZenExpression.Compile("a + b * 2"); var output = expr.Evaluate(new JsonBuffer("{\"a\": 1, \"b\": 10}")); +Console.WriteLine($"output: {output}"); expr.Dispose(); ``` @@ -92,5 +93,5 @@ var engine = new ZenEngine(loader: new FileLoader(), customNode: new MyCustomNod ## Links - [GitHub Repository](https://github.com/gorules/zen) -- [GoRules Documentation](https://gorules.io/docs) +- [GoRules Documentation](https://gorules.mintlify.app/developers/sdks/csharp) - [JDM Editor](https://editor.gorules.io) diff --git a/bindings/uniffi/nuget/icon.png b/bindings/uniffi/nuget/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b3199c44454b62a97da3583d5d82e2d4730b08d0 GIT binary patch literal 8564 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 Date: Thu, 26 Feb 2026 08:41:01 +0100 Subject: [PATCH 16/18] docs link --- bindings/uniffi/nuget/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/uniffi/nuget/README.md b/bindings/uniffi/nuget/README.md index 2fd72fd9..858647c5 100644 --- a/bindings/uniffi/nuget/README.md +++ b/bindings/uniffi/nuget/README.md @@ -93,5 +93,5 @@ var engine = new ZenEngine(loader: new FileLoader(), customNode: new MyCustomNod ## Links - [GitHub Repository](https://github.com/gorules/zen) -- [GoRules Documentation](https://gorules.mintlify.app/developers/sdks/csharp) +- [GoRules Documentation](https://docs.gorules.io/developers/sdks/csharp) - [JDM Editor](https://editor.gorules.io) From 847af2224040872b1a955e70d81133ea3cd57732 Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Thu, 26 Feb 2026 15:35:41 +0100 Subject: [PATCH 17/18] readme fix --- bindings/uniffi/nuget/README.md | 47 +++++++++++++++++---------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/bindings/uniffi/nuget/README.md b/bindings/uniffi/nuget/README.md index 858647c5..10c9a593 100644 --- a/bindings/uniffi/nuget/README.md +++ b/bindings/uniffi/nuget/README.md @@ -13,21 +13,13 @@ dotnet add package GoRules.ZenEngine ```csharp using GoRules.ZenEngine; -// Create engine and evaluate -var engine = new ZenEngine(loader: new FileLoader(), customNode: null); -var context = new JsonBuffer("{\"input\": 42}"); -var response = await engine.Evaluate("my-decision.json", context, null); -Console.WriteLine(response.result.ToString()); +// Create an engine and evaluate +var engine = new ZenEngine(loader: null, customNode: null); +var decision = engine.CreateDecision(new JsonBuffer(File.ReadAllBytes("my-decision.json"))); +var context = new JsonBuffer("""{"input": 42}"""); +var response = await decision.Evaluate(context, null); +Console.WriteLine(response.result); -// Implement a loader to resolve decision files -class FileLoader : ZenDecisionLoaderCallback -{ - public Task Load(string key) - { - var bytes = File.ReadAllBytes(key); - return Task.FromResult(new JsonBuffer(bytes)); - } -} ``` ## Features @@ -44,9 +36,9 @@ Enable tracing to inspect the execution of each node: ```csharp var options = new ZenEvaluateOptions(maxDepth: null, trace: true); -var response = await engine.Evaluate("decision.json", context, options); +var decided = await decision.Evaluate(context, options); -foreach (var (nodeId, trace) in response.trace!) +foreach (var (nodeId, trace) in decided.trace!) { Console.WriteLine($"{trace.name}: {trace.output}"); } @@ -75,19 +67,28 @@ expr.Dispose(); Extend the engine with custom logic: ```csharp + +using var myEngine = new ZenEngine(loader: new FileLoader(), customNode: new MyCustomNode()); +var myResponse = await myEngine.Evaluate("custom.json", context, options); +Console.WriteLine(myResponse.result); + +// Custom node handler class MyCustomNode : ZenCustomNodeCallback { - public Task Handle(ZenEngineHandlerRequest request) - { - var output = new JsonBuffer("{\"result\": \"custom\"}"); - return Task.FromResult(new ZenEngineHandlerResponse( - output: output, + public Task Handle(ZenEngineHandlerRequest request) => + Task.FromResult(new ZenEngineHandlerResponse( + output: new JsonBuffer("""{"result": "custom"}"""), traceData: null )); - } } -var engine = new ZenEngine(loader: new FileLoader(), customNode: new MyCustomNode()); +// Implement a loader to resolve decision files +class FileLoader : ZenDecisionLoaderCallback +{ + public Task Load(string key) => + Task.FromResult(new JsonBuffer(File.ReadAllBytes(key))); +} + ``` ## Links From 045ed44f6bf5643e4e78b7cf48909c95bd8252f4 Mon Sep 17 00:00:00 2001 From: bojancrevar Date: Fri, 27 Feb 2026 11:59:25 +0100 Subject: [PATCH 18/18] remove workflow dispatch --- .github/workflows/uniffi.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/uniffi.yaml b/.github/workflows/uniffi.yaml index 16e35424..8052c534 100644 --- a/.github/workflows/uniffi.yaml +++ b/.github/workflows/uniffi.yaml @@ -3,7 +3,6 @@ env: UNIFFI_DIRECTORY: bindings/uniffi on: - workflow_dispatch: push: branches: - master @@ -80,7 +79,7 @@ jobs: release-java-kotlin: runs-on: ubuntu-latest needs: [ build ] - if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi') && github.event_name != 'workflow_dispatch'" + if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi')" defaults: run: working-directory: ${{ env.UNIFFI_DIRECTORY }} @@ -143,7 +142,7 @@ jobs: needs: [ build ] permissions: id-token: write # Required for OIDC - if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi') || github.event_name == 'workflow_dispatch'" + if: "startsWith(github.event.head_commit.message, 'chore(release): publish uniffi')" defaults: run: working-directory: ${{ env.UNIFFI_DIRECTORY }} @@ -215,7 +214,7 @@ jobs: --skip-duplicate build-ios: - if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" + if: "!contains(github.event.head_commit.message, 'skip ci')" env: OUTPUT_NAME: zen_uniffi IPHONEOS_DEPLOYMENT_TARGET: '16.0' @@ -429,7 +428,7 @@ jobs: --base "master" build-android: - if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" + if: "!contains(github.event.head_commit.message, 'skip ci')" runs-on: ubuntu-latest env: OUTPUT_NAME: zen_uniffi @@ -476,7 +475,7 @@ jobs: prepare-android-bindings: runs-on: ubuntu-latest needs: [ build ] - if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'workflow_dispatch'" + if: "!contains(github.event.head_commit.message, 'skip ci')" defaults: run: