Smplkit.Sdk
3.5.91
dotnet add package Smplkit.Sdk --version 3.5.91
NuGet\Install-Package Smplkit.Sdk -Version 3.5.91
<PackageReference Include="Smplkit.Sdk" Version="3.5.91" />
<PackageVersion Include="Smplkit.Sdk" Version="3.5.91" />
<PackageReference Include="Smplkit.Sdk" />
paket add Smplkit.Sdk --version 3.5.91
#r "nuget: Smplkit.Sdk, 3.5.91"
#:package Smplkit.Sdk@3.5.91
#addin nuget:?package=Smplkit.Sdk&version=3.5.91
#tool nuget:?package=Smplkit.Sdk&version=3.5.91
smplkit C# SDK
The official C# SDK for smplkit — simple application infrastructure that just works.
Installation
dotnet add package Smplkit.Sdk
Requirements
- .NET 8.0+
Quick Start
using Smplkit;
// Option 1: Explicit API key
var client = new SmplClient(new SmplClientOptions { ApiKey = "sk_api_..." });
// Option 2: Environment variable (SMPLKIT_API_KEY)
// export SMPLKIT_API_KEY=sk_api_...
var client2 = new SmplClient();
// Option 3: Configuration file (~/.smplkit)
// [default]
// api_key = sk_api_...
var client3 = new SmplClient();
using Smplkit;
using Smplkit.Config;
using var client = new SmplClient(new SmplClientOptions
{
ApiKey = "sk_api_...",
Environment = "production",
Service = "my-service",
});
// Runtime: resolve config values for the current environment (lazy-loaded, cached)
var values = client.Config.Get("user_service");
var timeout = values["timeout"];
// Typed deserialization
var cfg = client.Config.Get<MyServiceConfig>("user_service");
// Management: create, get, list, delete
var newConfig = client.Manage.Config.New(
id: "my_service",
name: "My Service",
description: "Configuration for my service");
newConfig.SetNumber("timeout", 30);
newConfig.SetNumber("retries", 3);
await newConfig.SaveAsync();
var existing = await client.Manage.Config.GetAsync("user_service");
var all = await client.Manage.Config.ListAsync();
await client.Manage.Config.DeleteAsync("my_service");
Flags
Feature flags with local JSON Logic evaluation, typed handles, and real-time updates:
using Smplkit;
using Smplkit.Flags;
using var client = new SmplClient(new SmplClientOptions
{
ApiKey = "sk_api_...",
Environment = "production",
Service = "my-service",
});
// Declare typed flag handles with code-level defaults
var checkout = client.Flags.BooleanFlag("checkout-v2", false);
var banner = client.Flags.StringFlag("banner-color", "red");
var retries = client.Flags.NumberFlag("max-retries", 3);
// Set ambient evaluation context once (e.g. from request middleware).
// The returned IDisposable reverts the context when disposed.
using var _ = client.SetContext(new[]
{
new Context("user", currentUser.Id, new Dictionary<string, object?>
{
["plan"] = currentUser.Plan,
}),
new Context("account", currentAccount.Id, new Dictionary<string, object?>
{
["region"] = currentAccount.Region,
}),
});
// Evaluate flags — local, typed, instant (no network per call).
// Definitions are fetched and the WebSocket opens on first .Get(); no
// explicit Connect call is required.
if (checkout.Get())
RenderNewCheckout();
var color = banner.Get(); // "blue", "red", etc.
var maxRetries = retries.Get(); // 5, 3, etc.
// Explicit context override (for background jobs, tests)
var result = checkout.Get(new List<Context>
{
new("user", "test-user", new Dictionary<string, object?> { ["plan"] = "free" }),
});
// Listen for real-time changes
client.Flags.OnChange(e => Console.WriteLine($"Flag {e.Id} changed via {e.Source}"));
Flag Management
// Create a flag
var flag = client.Manage.Flags.NewBooleanFlag(
"checkout-v2", defaultValue: false,
name: "Checkout V2", description: "New checkout experience");
// Add a rule and save
flag.AddRule(
new Rule("Enable for enterprise users")
.Environment("production")
.When("user.plan", "==", "enterprise")
.Serve(true)
.Build());
await flag.SaveAsync();
// Fetch, list, delete
var existing = await client.Manage.Flags.GetAsync("checkout-v2");
var all = await client.Manage.Flags.ListAsync();
await client.Manage.Flags.DeleteAsync("checkout-v2");
Logging
Dynamic, server-managed log levels for every category in your host's logging
pipeline. Wire smplkit into Microsoft.Extensions.Logging once and every
ILogger<T> in your app — including ones created before smplkit starts —
becomes auto-discovered and level-managed. Server-pushed level changes gate
output across every registered provider (Console, Debug, file sinks,
Serilog-via-MEL, etc.) — not just smplkit's own output.
using Microsoft.Extensions.Logging;
using Smplkit;
using Smplkit.Logging.Adapters;
using var client = new SmplClient(new SmplClientOptions
{
ApiKey = "sk_api_...",
Environment = "production",
Service = "my-service",
});
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
builder.AddSmplkit(client); // registers as ILoggerProvider +
// IConfigureOptions<LoggerFilterOptions> +
// IOptionsChangeTokenSource<...>
});
// Bulk-register every discovered category and apply current managed levels.
await client.Logging.InstallAsync();
// Any logger created in your app from this point on is auto-discovered.
var dbLogger = loggerFactory.CreateLogger("MyApp.Db");
dbLogger.LogInformation("Hello — server-managed level controls whether this is emitted");
// Re-fetch managed levels and re-apply them (rarely needed; the WebSocket
// pushes changes automatically).
await client.Logging.RefreshAsync();
// Listen for level changes
client.Logging.OnChange(e =>
Console.WriteLine($"Logger {e.Id} level → {e.Level} via {e.Source}"));
Inside an ASP.NET Core / Generic Host app the wiring is the same — the
ILoggingBuilder exposed by services.AddLogging(b => …) accepts
AddSmplkit(client) directly.
Logger Management
// Create / update a managed logger
var logger = client.Manage.Loggers.New("MyApp.Db");
logger.SetLevel(LogLevel.Warn);
await logger.SaveAsync();
// Fetch, list, delete
var existing = await client.Manage.Loggers.GetAsync("MyApp.Db");
var all = await client.Manage.Loggers.ListAsync();
await client.Manage.Loggers.DeleteAsync("MyApp.Db");
// Bulk-register explicit logger sources (e.g. seeding a fresh account or
// migrating fixtures across services). Defaults to immediate POST; pass
// flush=false to buffer multiple calls and FlushAsync to drain.
await client.Manage.Loggers.RegisterAsync(new[]
{
new LoggerSource("MyApp.Db", level: LogLevel.Info),
new LoggerSource("MyApp.Payments", level: LogLevel.Warn),
});
// Log groups follow the same shape (use to scope levels across many loggers).
var billing = client.Manage.LogGroups.New("billing");
billing.SetLevel(LogLevel.Debug);
await billing.SaveAsync();
Serilog
Serilog's single-root logger model has no equivalent of MEL's per-provider
factory, so smplkit-managed Serilog loggers must be wired explicitly via
SerilogAdapter.GetOrCreateSwitch:
using Serilog;
using Smplkit.Logging.Adapters;
var adapter = new SerilogAdapter();
client.Logging.RegisterAdapter(adapter);
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override("MyApp.Db", adapter.GetOrCreateSwitch("MyApp.Db"))
.MinimumLevel.Override("MyApp.Payments", adapter.GetOrCreateSwitch("MyApp.Payments"))
.WriteTo.Console()
.CreateLogger();
await client.Logging.InstallAsync();
Configuration
All settings are resolved from three sources, in order of precedence:
- Constructor options — highest priority, always wins.
- Environment variables — e.g.
SMPLKIT_API_KEY,SMPLKIT_ENVIRONMENT. - Configuration file (
~/.smplkit) — INI-format with profile support. - Defaults — built-in SDK defaults.
Configuration File
The ~/.smplkit file supports a [common] section (applied to all profiles) and named profiles:
[common]
environment = production
service = my-app
[default]
api_key = sk_api_abc123
[local]
base_domain = localhost
scheme = http
api_key = sk_api_local_xyz
environment = development
debug = true
Constructor Examples
// Use a named profile
var client = new SmplClient(new SmplClientOptions { Profile = "local" });
// Or configure explicitly
var client = new SmplClient(new SmplClientOptions
{
ApiKey = "sk_api_...",
Environment = "production",
Service = "my-service",
});
For the complete configuration reference, see the Configuration Guide.
Error Handling
All SDK errors extend SmplException:
using Smplkit.Errors;
try
{
var config = await client.Config.Management.GetAsync("nonexistent-id");
}
catch (SmplNotFoundException ex)
{
Console.WriteLine($"Not found: {ex.Message}");
}
catch (SmplException ex)
{
Console.WriteLine($"Status: {ex.StatusCode}, Body: {ex.ResponseBody}");
}
| Exception | Cause |
|---|---|
SmplNotFoundException |
HTTP 404 — resource not found |
SmplConflictException |
HTTP 409 — conflict |
SmplValidationException |
HTTP 422 — validation error |
SmplTimeoutException |
Request timed out |
SmplConnectionException |
Network connectivity issue |
SmplException |
Any other SDK error |
Cancellation
All async methods accept an optional CancellationToken:
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var configs = await client.Config.Management.ListAsync(cts.Token);
Debug Logging
Set the SMPLKIT_DEBUG environment variable to enable verbose diagnostic output to stderr:
export SMPLKIT_DEBUG=1
Accepted truthy values: 1, true, yes (case-insensitive). All other values (including unset) disable output.
Each line follows the format:
[smplkit:{subsystem}] {ISO-8601 timestamp} {message}
Subsystems: lifecycle, websocket, api, discovery, resolution, adapter, registration.
Output writes directly to Console.Error to avoid interference with the managed logging infrastructure.
Documentation
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- JsonLogic.Net (>= 1.1.11)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.5.91 | 33 | 5/22/2026 |
| 3.5.90 | 34 | 5/22/2026 |
| 3.5.89 | 32 | 5/22/2026 |
| 3.5.88 | 31 | 5/22/2026 |
| 3.5.87 | 39 | 5/21/2026 |
| 3.5.86 | 37 | 5/21/2026 |
| 3.5.85 | 35 | 5/21/2026 |
| 3.5.84 | 33 | 5/21/2026 |
| 3.5.83 | 35 | 5/21/2026 |
| 3.5.82 | 36 | 5/20/2026 |
| 3.5.81 | 67 | 5/20/2026 |
| 3.5.80 | 66 | 5/20/2026 |
| 3.5.79 | 80 | 5/19/2026 |
| 3.5.78 | 77 | 5/19/2026 |
| 3.5.77 | 80 | 5/19/2026 |
| 3.5.75 | 75 | 5/19/2026 |
| 3.5.74 | 73 | 5/19/2026 |
| 3.5.73 | 72 | 5/19/2026 |
| 3.5.72 | 88 | 5/18/2026 |
| 3.5.71 | 81 | 5/18/2026 |