@sundaeswap/sprinkles
v0.5.0
Published
A TypeScript library for building interactive CLI menus and TUI applications with TypeBox schema validation
Readme
Sprinkles
Note: This is an early release (v0.x). The API may change between minor versions as we refine the library based on community feedback.
A TypeScript library for building interactive CLI menus and TUI applications with TypeBox schema validation. Sprinkles provides a declarative way to create nested menus, handle user input, and manage persistent settings with type safety.
Features
- Schema-driven UI: Define your data structures using TypeBox schemas, and Sprinkles automatically generates interactive prompts
- Nested menu support: Create hierarchical menu structures with submenus
- Persistent settings: Automatic JSON-based settings storage with BigInt support
- Type-safe: Full TypeScript support with type inference from schemas
- Cardano integration: Built-in helpers for Blaze SDK wallet and provider management
- Transaction dialogs: Ready-to-use transaction signing and submission flows
Installation
npm install @sundaeswap/sprinklesQuick Start
import { Sprinkle, Type } from "sprinkles";
// Define your settings schema
const AppSettingsSchema = Type.Object({
username: Type.String({ title: "Username" }),
theme: Type.Union([
Type.Literal("dark"),
Type.Literal("light")
])
});
// Create a Sprinkle instance
const app = await Sprinkle.New(AppSettingsSchema, "./config");
// Define your menu
const mainMenu = {
title: "Main Menu",
items: [
{
title: "Say Hello",
action: async (sprinkle) => {
console.log(`Hello, ${sprinkle.settings.username}!`);
}
}
]
};
// Show the menu
await app.showMenu(mainMenu);API Reference
Core Classes
Sprinkle<S extends TSchema>
The main class for managing your CLI application.
Constructor
constructor(type: S, storagePath: string)Static Methods
Sprinkle.New<S>(type: S, storagePath: string): Promise<Sprinkle<S>>- Create and initialize a new Sprinkle instanceSprinkle.GetProvider(network, settings): Provider- Create a Cardano provider instanceSprinkle.GetWallet(settings, provider): Promise<Wallet>- Create a Cardano wallet instanceSprinkle.GetBlaze(network, providerSettings, walletSettings): Promise<Blaze>- Create a Blaze SDK instanceSprinkle.SettingsPath(storagePath: string): string- Get the settings file path
Instance Methods
showMenu(menu: IMenu<S>): Promise<void>- Display a menu and handle user interactionsEditStruct<U>(type: U, current: TExact<U>): Promise<TExact<U>>- Interactive editor for schema-based structuresFillInStruct<U>(type: U, def?: TExact<U>): Promise<TExact<U>>- Interactive form to fill in a structureTxDialog(blaze, tx): Promise<void>- Display transaction dialog with sign/submit optionssaveSettings(): void- Persist current settings to diskLoadSettings(type, storagePath): Promise<void>- Load settings from disk
Types
IMenu<S>
Defines a menu structure:
interface IMenu<S extends TSchema> {
title: string;
items: TMenuItem<S>[];
}IMenuAction<S>
Defines a menu action:
interface IMenuAction<S extends TSchema> {
title: string;
action: (sprinkle: Sprinkle<S>) => Promise<Sprinkle<S> | void>;
}TMenuItem<S>
A menu item can be either an action or a submenu:
type TMenuItem<S extends TSchema> = IMenuAction<S> | IMenu<S>;Built-in Schemas
NetworkSchema
Cardano network selection:
Type.Union([
Type.Literal("mainnet"),
Type.Literal("preview"),
Type.Literal("preprod")
])ProviderSettingsSchema
Cardano provider configuration:
Type.Union([
Type.Object({
type: Type.Literal("blockfrost"),
projectId: Type.String({ minLength: 1, title: "Blockfrost Project ID" })
}),
Type.Object({
type: Type.Literal("maestro"),
apiKey: Type.String({ minLength: 1, title: "Maestro API Key" })
})
])WalletSettingsSchema
Cardano wallet configuration:
Type.Union([
Type.Object({
type: Type.Literal("hot"),
privateKey: Type.String({ minLength: 1, title: "Hot Wallet Private Key" })
}),
Type.Object({
type: Type.Literal("cold"),
address: Type.String({ minLength: 1, title: "Cold Wallet Address" })
})
])MultisigScript
Cardano multisig script schema with support for:
- Signature verification
- AllOf (all signatures required)
- AnyOf (any signature works)
- AtLeast (m-of-n threshold)
- Before/After (time-based conditions)
- Script hash references
Advanced Usage
Creating Nested Menus
const menu = {
title: "Main Menu",
items: [
{
title: "User Management",
items: [
{
title: "Add User",
action: async (sprinkle) => {
// Add user logic
}
},
{
title: "Remove User",
action: async (sprinkle) => {
// Remove user logic
}
}
]
}
]
};Modifying Settings from Actions
{
title: "Change Username",
action: async (sprinkle) => {
const newSettings = await sprinkle.EditStruct(
Type.Object({ username: Type.String() }),
{ username: sprinkle.settings.username }
);
return new Sprinkle(sprinkle.type, sprinkle.storagePath);
}
}Working with Cardano Transactions
const blaze = await Sprinkle.GetBlaze(
"preprod",
providerSettings,
walletSettings
);
// Build your transaction
const tx = await blaze
.newTransaction()
.payLovelace(recipientAddress, 5_000_000n)
.complete();
// Show transaction dialog
await app.TxDialog(blaze, tx);Settings Persistence
Settings are automatically saved to {storagePath}/settings.json. The file format includes:
{
"settings": {
"username": "alice",
"count": "42n"
},
"defaults": {
"string": "last_entered_value"
}
}Note: BigInt values are serialized with an 'n' suffix and automatically parsed on load.
License
MIT
