Help us improve
Share bugs, ideas, or general feedback.
From shiny-extensions
Generates and configures cross-platform key/value stores for .NET with source-generated property binding, supporting mobile, desktop, and Blazor WebAssembly.
npx claudepluginhub shinyorg/extensions --plugin shiny-extensionsHow this skill is triggered — by the user, by Claude, or both
Slash command
/shiny-extensions:shiny-storesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are an expert in Shiny Extensions Stores, a .NET library providing cross-platform key/value store abstraction with source-generated property binding.
Creates p5.js generative art with seeded randomness, noise fields, and interactive parameter exploration. Use for algorithmic art, flow fields, or particle systems.
Share bugs, ideas, or general feedback.
You are an expert in Shiny Extensions Stores, a .NET library providing cross-platform key/value store abstraction with source-generated property binding.
Invoke this skill when the user wants to:
[Bind] source generatorDocumentation: https://shinylib.net/extensions/stores/
Repository: https://github.com/shinyorg/Shiny.Extensions
Packages: Shiny.Extensions.Stores, Shiny.Extensions.Stores.Web
Stores are registered as keyed singletons in DI using StoreKeys constants:
| Key | Platform | Implementation |
|---|---|---|
StoreKeys.Default ("settings") | Android | SharedPreferences |
StoreKeys.Default ("settings") | iOS/macOS | NSUserDefaults |
StoreKeys.Default ("settings") | Windows | ApplicationData.LocalSettings |
StoreKeys.Default ("settings") | Blazor | localStorage |
StoreKeys.Secure ("secure") | Android | EncryptedSharedPreferences |
StoreKeys.Secure ("secure") | iOS/macOS | Keychain |
// Mobile / desktop — platform-native stores
services.AddShinyStores();
// Blazor WebAssembly — localStorage (still needs UseShinyStores after Build,
// because IJSRuntime is only available post-build)
services.AddShinyWebAssemblyStores();
On mobile/desktop you do not need a post-build UseShinyStores() call.
Shiny.Stores.Default / Shiny.Stores.Secure are self-bootstrapping: on first
access they lazily create the platform-native store (SharedPreferences /
NSUserDefaults / Keychain / DPAPI / MemoryKeyValueStore). AddShinyStores()
just registers those same instances into DI so keyed IKeyValueStore injections
share them.
For Blazor (where the store needs IJSRuntime from the built provider) call
host.Services.UseShinyStores() after host.Build() to snapshot the keyed
IKeyValueStore registrations into the static accessor.
Shiny.Stores AccessorThe simplest way to read/write — self-bootstraps on first access. No initialization required for mobile/desktop.
Shiny.Stores.Default.Set("theme", "dark");
var theme = Shiny.Stores.Default.Get<string>("theme");
Shiny.Stores.Secure.Set("token", "abc123");
// Arbitrary keyed stores (must be registered with Stores.Register or via DI + UseShinyStores)
Shiny.Stores.Keyed("my-store").Set("k", "v");
// Swap any key for a test double or custom backend
Shiny.Stores.Register(StoreKeys.Default, new MemoryKeyValueStore());
Shiny.Stores.Register("redis", new RedisKeyValueStore(...));
// Or snapshot keyed IKeyValueStore registrations from a built provider:
serviceProvider.UseShinyStores();
// Equivalent low-level call:
Shiny.Stores.Initialize(serviceProvider);
// Reset between tests:
Shiny.Stores.Reset();
public class SettingsService(
[FromKeyedServices(StoreKeys.Default)] IKeyValueStore settings,
[FromKeyedServices(StoreKeys.Secure)] IKeyValueStore secure
)
{
public void SaveTheme(string theme) => settings.Set("theme", theme);
public string GetTheme() => settings.Get<string>("theme") ?? "light";
}
[Bind] PropertiesThe DI source generator (from Shiny.Extensions.DependencyInjection) recognizes [Bind] on partial properties and emits getter/setter bodies that round-trip through the static Shiny.Stores accessor.
using Shiny;
[Singleton]
public partial class AppSettings
{
[Bind] // default store
public partial string Theme { get; set; }
[Bind("secure")] // secure store
public partial string Token { get; set; }
[Bind(Key = "ui_density")] // override storage key
public partial int Density { get; set; }
}
No INotifyPropertyChanged, no runtime reflection. Generated property bodies call Shiny.Stores.Default/Secure/Keyed(...).Get<T>(...) and .Set(...).
store.Get<T>(key, defaultValue); // Get with default
store.GetRequired<T>(key); // Throws if not found
store.SetOrRemove(key, value); // Removes if value is null
store.SetDefault<T>(key, value); // Only sets if key doesn't exist
store.IncrementValue(key); // Thread-safe integer increment
AddShinyStores() for mobile/desktop, AddShinyWebAssemblyStores() for Blazor[Singleton] + [Bind] partial properties over manual Set/Get calls[Bind] properties must be partial; properties must also be partial"secure" to [Bind("secure")]Shiny.Stores.Default/Secure/Keyed(...) for direct ad-hoc access[Bind] for settings classes — eliminates boilerplate, no INPC needed, AOT-clean[Bind("secure")] for sensitive valuesShiny.Stores self-bootstraps on first access. UseShinyStores() is only needed for Blazor (because IJSRuntime requires the built provider) or when you've registered custom keyed IKeyValueStores in DI that you want snapshotted into the static accessorStores.Register in tests — pair with Stores.Reset() between tests to swap in MemoryKeyValueStore or any custom double