Shogun SDK Documentation v1.1.4 - v5.2.0

Shogun Core πŸ“¦

npm License TypeScript Ask DeepWiki

Shogun Core is a comprehensive SDK for building decentralized applications (dApps) that simplifies authentication, wallet management, and decentralized data storage. It combines GunDB's peer-to-peer networking with modern authentication standards and blockchain integration to provide a secure, user-friendly foundation for Web3 applications.

  • πŸ” Multiple Authentication Methods: Traditional username/password, WebAuthn (biometrics), Web3 (MetaMask), Nostr, and ZK-Proof (anonymous)
  • 🌐 Decentralized Storage: Built on GunDB for peer-to-peer data synchronization
  • πŸ”Œ Plugin System: Extensible architecture with built-in plugins for various authentication methods
  • πŸ’Ό Smart Wallet (Account Abstraction): Custom smart contract wallets with multi-sig, social recovery, and batch transactions
  • πŸ“± Reactive Programming: RxJS integration for real-time data streams
  • πŸ›‘οΈ Security: End-to-end encryption and secure key management
  • 🎯 TypeScript: Full TypeScript support with comprehensive type definitions
  • πŸ“‘ Event System: Typed event system for monitoring authentication and data changes
  • πŸ”‘ Password Recovery: Secure password hint system with security questions
  • βœ… Type Consistency: Unified return types across all authentication methods
  • πŸš€ Simplified Architecture: Focused on core functionality with reduced complexity
  • ⭐ Simple API: Easy-to-use wrapper for common operations with minimal complexity
  • πŸ”— Advanced Chaining: Powerful chaining operations for complex nested data structures
  • πŸ‘€ User Space Management: Complete CRUD operations for user-specific data storage
  • ⚑ Quick Start: Rapid initialization with pre-configured setups
  • πŸŽ›οΈ Configuration Presets: Pre-built configurations for common use cases
  • πŸ”§ FIXED: Remove Operations: Fixed critical bug in remove() and removeUserData() methods that was causing TypeError: Cannot read properties of null (reading 'err')
  • πŸ”§ IMPROVED: User Data Operations: Rewrote all user data methods to use direct Gun user node for better reliability and error handling
  • πŸ”§ ENHANCED: Error Handling: Added proper null checking and improved error logging throughout the user data operations
  • ⭐ STREAMLINED: Simple API Layer: Simplified SimpleGunAPI to focus on high-level helpers only
    • Direct database access via api.database for basic operations (get, put, auth, etc.)
    • Helper methods for standardized data: profile, settings, preferences, collections
    • Array/Object conversion utilities for GunDB
    • Removed redundant wrapper methods to reduce complexity
  • ⭐ NEW: Quick Start Functions: quickStart(), autoQuickStart() classes for rapid initialization
  • ⭐ NEW: Improved Type System: Reduced any usage with better TypeScript types
  • ⭐ NEW: Configuration Presets: Pre-built configurations for common use cases
  • ⭐ NEW: Advanced API Features: Comprehensive plugin management, peer network control, advanced user management, and security systems
  • Enhanced Advanced Features: Maintained and improved advanced plugin management, peer network management, and user tracking systems
  • Streamlined Event System: Enhanced event system with better type safety and comprehensive event handling
  • Improved Maintainability: Better organized codebase with clear separation of concerns
  • Better Performance: Optimized operations with reduced abstraction layers

Fixed Critical Remove Operations Bug:

  • Fixed TypeError: Cannot read properties of null (reading 'err') in remove() and removeUserData() methods
  • Added proper null checking: ack && ack.err instead of just ack.err
  • All user data operations now use direct Gun user node for better reliability
  • Improved error handling and logging throughout user data operations
  • 🚨 REMOVED: Array Functions: putUserArray(), getUserArray(), addToUserArray(), removeFromUserArray(), updateInUserArray() have been REMOVED due to GunDB compatibility issues
  • ⚠️ DEPRECATED: Global Array Functions: putArray(), getArray(), addToArray(), removeFromArray(), updateInArray() are deprecated and show warnings
  • βœ… MIGRATION: Use Collections or Direct GunDB Operations instead (see examples below)
  • Unified Return Types: All authentication methods now use consistent AuthResult and SignUpResult types
  • Enhanced SignUpResult: Extended to support provider-specific authentication data
  • Type Safety: Fixed TypeScript inconsistencies across all plugins
  • API Standardization: All plugins implement unified login() and signUp() interfaces
npm install shogun-core
# or
yarn add shogun-core
import { quickStart, Gun } from "shogun-core";

// Create Gun instance
const gun = Gun({
peers: ['https://gun-manhattan.herokuapp.com/gun']
});

// Quick start with simple API
const shogun = quickStart(gun, 'my-app');
await shogun.init();

// Use simplified API
const user = await shogun.api.signup('alice', 'password123');
if (user) {
console.log('User created:', user.username);

// User space operations
await shogun.api.updateProfile({
name: 'Alice',
email: 'alice@example.com'
});

await shogun.api.saveSettings({
theme: 'dark',
language: 'en'
});

// Create collections
await shogun.api.createCollection('todos', {
'1': { text: 'Learn Shogun Core', done: false },
'2': { text: 'Build dApp', done: false }
});
}
import { ShogunCore } from "shogun-core";

// Define your list of Gun peers
const relays = [
"wss://ruling-mastodon-improved.ngrok-free.app/gun",
"https://gun-manhattan.herokuapp.com/gun",
"https://peer.wallie.io/gun",
];

// Initialize Shogun Core with plugins
const shogun = new ShogunCore({
peers: relays,
scope: "my-awesome-app",
authToken: "YOUR_GUN_SUPER_PEER_SECRET", // Optional, for private peers

// Enable and configure Web3 (e.g., MetaMask) authentication
web3: {
enabled: true,
},

// Enable and configure WebAuthn (biometrics, security keys)
webauthn: {
enabled: true,
rpName: "My Awesome App", // Name of your application
rpId: window.location.hostname, // Relying party ID
},

// Enable and configure Nostr
nostr: {
enabled: true,
},

// Enable and configure ZK-Proof (anonymous authentication)
zkproof: {
enabled: true,
defaultGroupId: "my-app-users",
},

// Enable Smart Wallet (Account Abstraction)
smartwallet: {
enabled: true,
factoryAddress: "0x...", // Deployed SmartWalletFactory contract address
defaultRequiredSignatures: 1,
defaultRequiredGuardians: 2,
},
});

console.log("Shogun Core initialized!");

The Simple API provides an easy-to-use interface for common operations with minimal complexity. Perfect for beginners or when you need quick setup.

import { quickStart, Gun } from "shogun-core";

const gun = Gun({ peers: ['https://gun-manhattan.herokuapp.com/gun'] });
const shogun = quickStart(gun, 'my-app');
await shogun.init();

const api = shogun.api;
const db = api.database; // Access database directly for basic operations

// ===== BASIC OPERATIONS (use database) =====

// Authentication
const user = await db.signUp('username', 'password');
const loginResult = await db.login('username', 'password');
db.logout();
const isLoggedIn = db.isLoggedIn();

// Basic data operations
await db.put('path/to/data', { value: 'hello' });
const data = await db.getData('path/to/data');
await db.set('path/to/data', { value: 'updated' });
await db.remove('path/to/data');

// Gun node for advanced operations like .map()
const userNode = db.get('users');
userNode.map((user, userId) => console.log(`User ${userId}:`, user));

// ===== HELPER METHODS (use api) =====

// Profile management (standardized location)
await api.updateProfile({
name: 'John Doe',
email: 'john@example.com',
bio: 'Developer'
});
const profile = await api.getProfile();

// Settings and preferences (standardized locations)
await api.saveSettings({ language: 'en', notifications: true });
const settings = await api.getSettings();

await api.savePreferences({ theme: 'dark', fontSize: 14 });
const preferences = await api.getPreferences();

// Collections (standardized location for user collections)
await api.createCollection('todos', {
'1': { text: 'Learn Shogun Core', done: false },
'2': { text: 'Build dApp', done: false }
});

await api.addToCollection('todos', '3', {
text: 'Deploy to production',
done: false
});

const todos = await api.getCollection('todos');
await api.removeFromCollection('todos', '2');

// Array utilities for GunDB
const items = [
{ id: '1', name: 'Item 1' },
{ id: '2', name: 'Item 2' }
];
const indexed = api.arrayToIndexedObject(items); // Convert for GunDB storage
const restored = api.indexedObjectToArray(indexed); // Convert back

For advanced Gun.js operations, use the database instance directly via api.database or shogun.database:

const db = api.database; // or shogun.database

// Store nested data with Gun chaining
await db.get('users').get('alice').get('profile').put({
name: 'Alice Smith',
email: 'alice@example.com',
preferences: {
theme: 'dark',
language: 'en'
}
});

// Read nested data
const profile = await db.get('users').get('alice').get('profile').once().then();

// Update specific fields
await db.get('users').get('alice').get('profile').get('preferences').get('theme').put('light');

// Iterate over collections with .map()
db.get('users').map((user, userId) => {
console.log(`User ${userId}:`, user);
});

// Complex chaining for nested structures
await db.get('projects').get('my-app').get('tasks').get('1').put({
title: 'Implement authentication',
status: 'completed',
assignee: 'alice'
});

// Access Gun instance directly if needed
const gunInstance = db.gun;
gunInstance.get('some-path').on((data) => {
console.log('Real-time data:', data);
});
const db = shogun.database; // or api.database

// User management system
await db.get('users').get('alice').put({
profile: {
name: 'Alice',
email: 'alice@example.com'
},
settings: {
theme: 'dark',
notifications: true
},
posts: {
'1': { title: 'Hello World', content: 'My first post' },
'2': { title: 'GunDB is awesome', content: 'Learning decentralized storage' }
}
});

// Blog system
await db.get('blog').get('posts').get('2024-01-15').put({
title: 'Getting Started with Shogun Core',
author: 'alice',
content: 'Shogun Core makes decentralized apps easy...',
tags: ['tutorial', 'decentralized', 'web3'],
comments: {
'1': { author: 'bob', text: 'Great tutorial!' },
'2': { author: 'charlie', text: 'Very helpful, thanks!' }
}
});

// E-commerce system
await db.get('shop').get('products').get('laptop-001').put({
name: 'Gaming Laptop',
price: 1299.99,
stock: 15,
reviews: {
'1': { user: 'alice', rating: 5, comment: 'Amazing performance!' },
'2': { user: 'bob', rating: 4, comment: 'Good value for money' }
}
});

// Read complex nested data
const product = await db.get('shop').get('products').get('laptop-001').once().then();
console.log('Product:', product.name);
console.log('Reviews:', product.reviews);

// Update nested data
await db.get('shop').get('products').get('laptop-001').get('stock').put(12);
  1. Use api.database or shogun.database for direct Gun operations
  2. Use api helper methods for standardized data - profile, settings, collections
  3. Keep paths descriptive - Use meaningful path segments like users/alice/profile
  4. Handle errors appropriately - Chaining operations can fail, always check results
  5. Use helper methods for conventions - updateProfile(), saveSettings(), etc. provide standardized locations

Shogun Core provides a unified plugin system for different authentication methods. Each plugin implements standardized login() and signUp() methods that return consistent AuthResult and SignUpResult objects.

// Authentication result interface - used by login methods
interface AuthResult {
success: boolean;
error?: string;
userPub?: string; // User's public key
username?: string; // Username or identifier
sessionToken?: string; // Session token if applicable
authMethod?: AuthMethod; // Authentication method used
sea?: {
// GunDB SEA pair for session persistence
pub: string;
priv: string;
epub: string;
epriv: string;
};
// External auth flow properties
redirectUrl?: string; // Redirect URL for external auth
pendingAuth?: boolean; // Indicates pending auth flow
message?: string; // Status message
provider?: string; // Provider name
isNewUser?: boolean; // True if this was a registration
user?: {
// User data
userPub?: string;
username?: string;
email?: string;
name?: string;
picture?: string;
};
}

// Sign up result interface - used by signUp methods βœ… ENHANCED
interface SignUpResult {
success: boolean;
userPub?: string;
username?: string;
pub?: string;
error?: string;
message?: string;
wallet?: any;
isNewUser?: boolean;
authMethod?: AuthMethod; // βœ… ADDED
sessionToken?: string; // βœ… ADDED
sea?: { pub: string; priv: string; epub: string; epriv: string }; // SEA pair for session persistence
// Multi-device support (WebAuthn and ZK-Proof)
seedPhrase?: string; // BIP39 mnemonic or trapdoor for account recovery
// External auth flow support
redirectUrl?: string;
pendingAuth?: boolean;
provider?: string;
}

// Supported authentication methods
type AuthMethod =
| "password"
| "webauthn"
| "web3"
| "nostr"
| "zkproof"
| "pair";

Direct username/password authentication using ShogunCore methods:

// Sign up a new user - Returns SignUpResult βœ…
const signUpResult: SignUpResult = await shogun.signUp("username", "password");
if (signUpResult.success) {
console.log("User created:", signUpResult.username);
console.log("Is new user:", signUpResult.isNewUser);
console.log("Auth method:", signUpResult.authMethod);
}

// Login with username and password - Returns AuthResult βœ…
const loginResult: AuthResult = await shogun.login("username", "password");
if (loginResult.success) {
console.log("Logged in as:", loginResult.username);
console.log("User public key:", loginResult.userPub);
}

Ethereum wallet authentication via MetaMask or other Web3 providers:

const web3Plugin = shogun.getPlugin<Web3ConnectorPlugin>("web3");

if (web3Plugin && web3Plugin.isAvailable()) {
// Connect to MetaMask
const connectionResult = await web3Plugin.connectMetaMask();

if (connectionResult.success) {
const address = connectionResult.address!;

// Login with Web3 wallet - Returns AuthResult βœ…
const loginResult: AuthResult = await web3Plugin.login(address);
if (loginResult.success) {
console.log("Web3 login successful");
console.log("User public key:", loginResult.userPub);
}

// Register new user with Web3 wallet - Returns SignUpResult βœ…
const signUpResult: SignUpResult = await web3Plugin.signUp(address);
if (signUpResult.success) {
console.log("Web3 registration successful");
console.log("Is new user:", signUpResult.isNewUser);
}
}
}

// Plugin Interface - βœ… FIXED TYPES
interface Web3ConnectorPluginInterface {
// Authentication methods
login(address: string): Promise<AuthResult>; // βœ… CORRECT
signUp(address: string): Promise<SignUpResult>; // βœ… FIXED

// Connection methods
isAvailable(): boolean;
connectMetaMask(): Promise<ConnectionResult>;
getProvider(): Promise<ethers.JsonRpcProvider | ethers.BrowserProvider>;
getSigner(): Promise<ethers.Signer>;

// Credential management
generateCredentials(address: string): Promise<ISEAPair>;
generatePassword(signature: string): Promise<string>;
verifySignature(message: string, signature: string): Promise<string>;
}

Biometric and hardware key authentication with multi-device support via seed phrase:

const webauthnPlugin = shogun.getPlugin<WebauthnPlugin>("webauthn");

if (webauthnPlugin && webauthnPlugin.isSupported()) {
// ⭐ NEW: Register with seed phrase for multi-device support
const signUpResult: SignUpResult = await webauthnPlugin.signUp("username", {
generateSeedPhrase: true // Generate BIP39 seed phrase (default: true)
});

if (signUpResult.success) {
console.log("WebAuthn registration successful");
console.log("User public key:", signUpResult.userPub);

// ⚠️ CRITICAL: Display seed phrase to user for backup
if (signUpResult.seedPhrase) {
console.log("πŸ”‘ SAVE THESE 12 WORDS:");
console.log(signUpResult.seedPhrase);
alert(`IMPORTANT: Write down these 12 words to access your account from other devices:\n\n${signUpResult.seedPhrase}`);
}
}

// ⭐ NEW: Import account on another device using seed phrase
const importResult = await webauthnPlugin.importFromSeed(
"username",
"word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12"
);

if (importResult.success) {
console.log("Account imported successfully!");
}

// Authenticate existing user - Returns AuthResult βœ…
const loginResult: AuthResult = await webauthnPlugin.login("username");
if (loginResult.success) {
console.log("WebAuthn authentication successful");
console.log("Auth method:", loginResult.authMethod); // "webauthn"
}
}

// Plugin Interface - βœ… FIXED TYPES
interface WebauthnPluginInterface {
// Authentication methods
login(username: string): Promise<AuthResult>; // βœ… CORRECT
signUp(username: string): Promise<SignUpResult>; // βœ… FIXED

// Capability checks
isSupported(): boolean;

// WebAuthn-specific methods
register(username: string, displayName?: string): Promise<WebAuthnCredential>;
authenticate(username?: string): Promise<WebAuthnCredential>;
generateCredentials(
username: string,
pair?: ISEAPair | null,
login?: boolean
): Promise<WebAuthnUniformCredentials>;
}

Bitcoin wallet and Nostr protocol authentication:

const nostrPlugin = shogun.getPlugin<NostrConnectorPlugin>("nostr");

if (nostrPlugin && nostrPlugin.isAvailable()) {
// Connect to Nostr wallet (Bitcoin extension)
const connectionResult = await nostrPlugin.connectNostrWallet();

if (connectionResult.success) {
const address = connectionResult.address!;

// Login with Nostr/Bitcoin wallet - Returns AuthResult βœ…
const loginResult: AuthResult = await nostrPlugin.login(address);
if (loginResult.success) {
console.log("Nostr login successful");
console.log("Auth method:", loginResult.authMethod); // "nostr"
}

// Register with Nostr/Bitcoin wallet - Returns SignUpResult βœ…
const signUpResult: SignUpResult = await nostrPlugin.signUp(address);
if (signUpResult.success) {
console.log("Nostr registration successful");
console.log("Is new user:", signUpResult.isNewUser);
}
}
}

// Plugin Interface - βœ… FIXED TYPES
interface NostrConnectorPluginInterface {
// Authentication methods
login(address: string): Promise<AuthResult>; // βœ… CORRECT
signUp(address: string): Promise<SignUpResult>; // βœ… FIXED

// Connection methods
isAvailable(): boolean;
connectBitcoinWallet(
type?: "alby" | "nostr" | "manual"
): Promise<ConnectionResult>;
connectNostrWallet(): Promise<ConnectionResult>;

// Credential and signature management
generateCredentials(
address: string,
signature: string,
message: string
): Promise<NostrConnectorCredentials>;
verifySignature(
message: string,
signature: string,
address: string
): Promise<boolean>;
generatePassword(signature: string): Promise<string>;
}

Zero-Knowledge Proof authentication for anonymous, privacy-preserving authentication:

const zkPlugin = shogun.getPlugin<ZkProofPlugin>("zkproof");

if (zkPlugin && zkPlugin.isAvailable()) {
// Sign up with ZK-Proof (creates anonymous identity)
const signUpResult: SignUpResult = await zkPlugin.signUp();

if (signUpResult.success) {
console.log("ZK-Proof registration successful");
console.log("Public commitment:", signUpResult.username);

// ⚠️ CRITICAL: Display trapdoor to user for backup
if (signUpResult.seedPhrase) {
console.log("πŸ”‘ SAVE THIS TRAPDOOR:");
console.log(signUpResult.seedPhrase);
alert(`IMPORTANT: Save this trapdoor to access your account:\n\n${signUpResult.seedPhrase}`);
}
}

// Login with trapdoor (anonymous authentication)
const loginResult: AuthResult = await zkPlugin.login(trapdoor);
if (loginResult.success) {
console.log("ZK-Proof login successful (anonymous)");
console.log("Auth method:", loginResult.authMethod); // "zkproof"
}
}

// Plugin Interface
interface ZkProofPluginInterface {
// Authentication methods
login(trapdoor: string): Promise<AuthResult>;
signUp(seed?: string): Promise<SignUpResult>;

// ZK identity management
generateIdentity(seed?: string): Promise<ZkIdentityData>;
restoreIdentity(trapdoor: string): Promise<ZkIdentityData>;
generateCredentials(identityData: ZkIdentityData): Promise<ISEAPair>;

// ZK proof operations
generateProof(identityData: ZkIdentityData, options?: ZkProofGenerationOptions): Promise<any>;
verifyProof(proof: any, treeDepth?: number): Promise<ZkProofVerificationResult>;

// Group management
addToGroup(commitment: string, groupId?: string): void;
isAvailable(): boolean;
}

Advanced: Verifiable Credentials

ZK-Proof can also be used to prove attributes without revealing sensitive data:

import { ZkCredentials, CredentialType } from "shogun-core";

const zkCreds = new ZkCredentials();
const identity = await zkPlugin.generateIdentity();

// Prove age without revealing birthdate
const ageProof = await zkCreds.proveAge(
identity,
new Date("1990-01-01"),
18
);
// βœ… Proves: "I am 18 or older"
// ❌ Does NOT reveal: actual birthdate or exact age

// Prove citizenship without revealing country
const citizenshipProof = await zkCreds.proveCitizenship(
identity,
"Italy",
"EU"
);
// βœ… Proves: "I am an EU citizen"
// ❌ Does NOT reveal: specific country or passport number

// Prove education without revealing institution
const eduProof = await zkCreds.proveEducation(
identity,
"Bachelor of Science",
"MIT",
2020
);
// βœ… Proves: "I have a Bachelor of Science degree"
// ❌ Does NOT reveal: university name or grades

// Prove income without revealing exact amount
const incomeProof = await zkCreds.proveIncome(
identity,
75000,
50000,
"USD"
);
// βœ… Proves: "Income β‰₯ $50,000"
// ❌ Does NOT reveal: exact salary or employer

Use Cases:

  • Anonymous authentication
  • Age verification (18+, 21+, etc.)
  • Citizenship/residency proofs
  • Education credentials
  • Income verification for loans
  • Employment status
  • KYC compliance without revealing PII
  • Anonymous voting and polls

See src/examples/zkproof-credentials-example.ts for complete examples.

Feature Password WebAuthn Web3 Nostr ZK-Proof Smart Wallet
Anonymous ❌ ❌ ❌ ❌ βœ… ❌
Multi-device βœ… βœ… (seed) βœ… βœ… βœ… (trapdoor) βœ… (seed)
Hardware-free βœ… ❌ ❌ ❌ βœ… βœ…
Privacy ⚠️ ⚠️ ⚠️ ⚠️ βœ… ⚠️
No wallet needed βœ… βœ… ❌ ❌ βœ… ⚠️ (needs factory)
Verifiable credentials ❌ ❌ ❌ ❌ βœ… ❌
Group membership proofs ❌ ❌ ❌ ❌ βœ… ❌
Multi-sig support ❌ ❌ ❌ ❌ ❌ βœ…
Social recovery ❌ ❌ ❌ ❌ ❌ βœ…
Account Abstraction ❌ ❌ ❌ ❌ ❌ βœ…
Ease of use βœ…βœ…βœ… βœ…βœ… βœ…βœ… βœ…βœ… βœ…βœ… βœ…

Quick Setup:

# Install dependencies
yarn add shogun-core

# For ZK-Proof circuit files (optional, for advanced proofs)
cd shogun-core
yarn setup:zkproof

# Run examples
yarn zkproof:example
yarn zkproof:credentials

Account Abstraction with custom smart contract wallets supporting multi-sig, social recovery, and batch transactions:

const smartWalletPlugin = shogun.getPlugin<SmartWalletPlugin>("smartwallet");

// Configure signer (derive EOA from WebAuthn seed phrase)
const signUpResult = await webauthnPlugin.signUp("alice", {
generateSeedPhrase: true
});

const wallet = await derive(signUpResult.seedPhrase!, "alice", {
includeSecp256k1Ethereum: true
});

// Set signer with derived private key
await smartWalletPlugin.setSigner(wallet.secp256k1Ethereum.privateKey);

// Create Smart Wallet with guardians
const result = await smartWalletPlugin.createWalletWithGuardians(
wallet.secp256k1Ethereum.address,
[guardian1, guardian2],
1, // 1 signature required
2 // 2 guardians for recovery
);

if (result.success) {
console.log("Smart Wallet created:", result.walletAddress);
}

// Execute transactions
await smartWalletPlugin.executeTransaction(
result.walletAddress!,
targetAddress,
calldata,
"0"
);

// Social Recovery
await smartWalletPlugin.initiateRecovery(
result.walletAddress!,
newOwnerAddress
);

Features:

  • πŸ” Multi-Signature: Configure required signatures for transactions
  • πŸ‘₯ Social Recovery: Guardian-based recovery with timelock
  • ⚑ Batch Transactions: Save gas with multiple operations
  • πŸ”‘ Seed Phrase Integration: Derive EOA from WebAuthn seed phrase
  • πŸ’Ό Account Abstraction: Smart contract wallets with custom logic

Full Integration Example:

import { ShogunCore } from "shogun-core";
import { derive } from "shogun-core/gundb/derive";

const shogun = new ShogunCore({
peers: ["https://gun-manhattan.herokuapp.com/gun"],
scope: "my-app",
webauthn: { enabled: true },
smartwallet: {
enabled: true,
factoryAddress: "0x..." // Deployed SmartWalletFactory
},
});

// 1. Register with WebAuthn
const webauthnPlugin = shogun.getPlugin("webauthn");
const signUpResult = await webauthnPlugin.signUp("alice", {
generateSeedPhrase: true
});

// 2. Derive Ethereum wallet from seed phrase
const wallet = await derive(signUpResult.seedPhrase!, "alice", {
includeSecp256k1Ethereum: true
});

// 3. Setup Smart Wallet
const smartWalletPlugin = shogun.getPlugin("smartwallet");
await smartWalletPlugin.setSigner(wallet.secp256k1Ethereum.privateKey);

// 4. Create Smart Wallet
const walletResult = await smartWalletPlugin.createWalletWithGuardians(
wallet.secp256k1Ethereum.address,
[guardian1, guardian2],
1,
2
);

console.log("EOA:", wallet.secp256k1Ethereum.address);
console.log("Smart Wallet:", walletResult.walletAddress);

WebAuthn authentication now supports multi-device access through BIP39 seed phrases, solving the device-bound limitation of traditional WebAuthn.

WebAuthn credentials are device-specific by design:

  • Each device generates unique, non-exportable credentials
  • Cannot transfer credentials between devices
  • Changing devices means losing access to your account

When you register with WebAuthn, Shogun Core generates a 12-word BIP39 mnemonic (seed phrase):

const signUpResult = await webauthnPlugin.signUp("alice", {
generateSeedPhrase: true // Default: true
});

// ⚠️ CRITICAL: User MUST save these words!
console.log("Your seed phrase:", signUpResult.seedPhrase);
// Example: "abandon ability able about above absent absorb abstract absurd abuse access accident"

βœ… Same Account, Multiple Devices: Access your account from any device βœ… Account Recovery: Restore access if you lose your device βœ… Decentralized: No need for password reset emails or centralized recovery βœ… Compatible: Works with any BIP39-compatible wallet βœ… Secure: 128-bit entropy, cryptographically secure

const webauthnPlugin = shogun.getPlugin<WebauthnPlugin>("webauthn");

// Register with Face ID
const result = await webauthnPlugin.signUp("alice", {
generateSeedPhrase: true
});

if (result.success && result.seedPhrase) {
// Display to user with clear warning
showSeedPhraseBackupUI(result.seedPhrase);
// Example: "ability abandon about above absent absorb abstract absurd abuse access accident account"
}
// User enters their 12-word seed phrase
const seedPhrase = getUserInputSeedPhrase();

// Import account using seed phrase
const result = await webauthnPlugin.importFromSeed("alice", seedPhrase);

if (result.success) {
console.log("Account imported! You can now use Windows Hello.");
}
// React component for seed phrase backup
function SeedPhraseBackup({ seedPhrase }: { seedPhrase: string }) {
const words = seedPhrase.split(' ');

return (
<div className="seed-phrase-backup">
<h2>πŸ”‘ Save Your Recovery Phrase</h2>
<p><strong>Write down these 12 words in order</strong></p>
<p className="warning">
⚠️ Without these words, you cannot recover your account or access it from other devices!
</p>

<div className="word-grid">
{words.map((word, index) => (
<div key={index} className="word-item">
<span className="word-number">{index + 1}.</span>
<span className="word-text">{word}</span>
</div>
))}
</div>

<div className="actions">
<button onClick={() => downloadSeedPhrase(seedPhrase)}>
πŸ“₯ Download as Text File
</button>
<button onClick={() => printSeedPhrase(seedPhrase)}>
πŸ–¨οΈ Print on Paper
</button>
</div>

<label>
<input type="checkbox" required />
I have safely stored my 12-word recovery phrase
</label>
</div>
);
}
  1. Never store seed phrases digitally - Write them on paper
  2. Keep multiple backups - Store in different secure locations
  3. Never share your seed phrase - Anyone with it can access your account
  4. Verify before moving on - Double-check you wrote it correctly
  5. Use steel backup - For maximum durability (fire/water proof)

If you don't need multi-device support, you can disable seed phrase generation:

const result = await webauthnPlugin.signUp("alice", {
generateSeedPhrase: false // Device-bound only
});
// No seed phrase returned - traditional WebAuthn behavior

You can also use Shogun Core directly in the browser by including it from a CDN. This is ideal for static sites or lightweight applications.

<!DOCTYPE html>
<html>
<head>
<title>Shogun Core in Browser</title>
</head>
<body>
<h1>My dApp</h1>
<!-- Required dependencies for Shogun Core -->
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gun/sea.js"></script>

<!-- Shogun Core library -->
<script src="https://cdn.jsdelivr.net/npm/shogun-core/dist/browser/shogun-core.js"></script>

<script>
// Access the global Shogun Core function
const shogunCore = window.SHOGUN_CORE({
peers: ["https://gun-manhattan.herokuapp.com/gun"],
scope: "my-browser-app",
web3: { enabled: true },
webauthn: {
enabled: true,
rpName: "My Browser dApp",
rpId: window.location.hostname,
},
});

console.log("Shogun Core initialized in browser!", shogunCore);

async function connectWallet() {
if (shogunCore.hasPlugin("web3")) {
const web3Plugin = shogunCore.getPlugin("web3");
try {
const provider = await web3Plugin.getProvider();
const signer = provider.getSigner();
const address = await signer.getAddress();
await web3Plugin.login(address);
console.log("Logged in with address:", address);
} catch (error) {
console.error("Web3 login failed:", error);
}
}
}
</script>
</body>
</html>
  • signup(username: string, password: string): Promise<UserInfo | null> - Create new user account
  • login(username: string, password: string): Promise<UserInfo | null> - Authenticate with username/password
  • logout(): void - Logout current user
  • isLoggedIn(): boolean - Check if user is authenticated
  • get<T>(path: string): Promise<T | null> - Get data from path
  • put<T>(path: string, data: T): Promise<boolean> - Store data at path
  • set<T>(path: string, data: T): Promise<boolean> - Update data at path
  • remove(path: string): Promise<boolean> - Remove data from path
  • node(path: string): GunNode - Get Gun node for direct chaining (recommended)
  • chain(path: string): ChainingWrapper - Get simplified chaining wrapper
  • getNode(path: string): GunNode - Get Gun node for advanced operations like .map()
  • putUserData<T>(path: string, data: T): Promise<boolean> - Store user-specific data
  • getUserData<T>(path: string): Promise<T | null> - Get user-specific data
  • setUserData<T>(path: string, data: T): Promise<boolean> - Update user-specific data
  • removeUserData(path: string): Promise<boolean> - Remove user-specific data
  • getAllUserData(): Promise<Record<string, unknown> | null> - Get all user data
  • updateProfile(profileData: ProfileData): Promise<boolean> - Update user profile
  • getProfile(): Promise<Record<string, unknown> | null> - Get user profile
  • saveSettings(settings: Record<string, unknown>): Promise<boolean> - Save user settings
  • getSettings(): Promise<Record<string, unknown> | null> - Get user settings
  • savePreferences(preferences: Record<string, unknown>): Promise<boolean> - Save user preferences
  • getPreferences(): Promise<Record<string, unknown> | null> - Get user preferences
  • createCollection<T>(name: string, items: Record<string, T>): Promise<boolean> - Create user collection
  • addToCollection<T>(name: string, itemId: string, item: T): Promise<boolean> - Add item to collection
  • getCollection(name: string): Promise<Record<string, unknown> | null> - Get collection
  • removeFromCollection(name: string, itemId: string): Promise<boolean> - Remove item from collection
  • arrayToIndexedObject<T>(arr: T[]): Record<string, T> - Convert array to indexed object (helper)
  • indexedObjectToArray<T>(indexedObj: Record<string, T>): T[] - Convert indexed object to array (helper)

The following array functions have been REMOVED due to GunDB compatibility issues:

  • putUserArray(), getUserArray(), addToUserArray(), removeFromUserArray(), updateInUserArray()

Use collections or direct GunDB operations instead (see examples above).

  • login(username: string, password: string): Promise<AuthResult> - Authenticate with username/password
  • loginWithPair(pair: ISEAPair): Promise<AuthResult> - Authenticate directly with a GunDB SEA pair
  • signUp(username: string, password: string, email?: string, pair?: ISEAPair | null): Promise<SignUpResult> - Create new user account
  • logout(): void - Logout current user
  • isLoggedIn(): boolean - Check if user is authenticated
  • setAuthMethod(method: AuthMethod): void - Set authentication method
  • getAuthMethod(): AuthMethod | undefined - Get current authentication method
  • saveCredentials(credentials: any): Promise<void> - Save user credentials
  • getPlugin<T>(name: string): T | undefined - Get plugin by name
  • hasPlugin(name: string): boolean - Check if plugin exists
  • register(plugin: ShogunPlugin): void - Register custom plugin
  • unregister(pluginName: string): void - Remove plugin
  • getPluginsInfo(): Array<{name: string; version: string; category?: PluginCategory; description?: string}> - Get detailed plugin information
  • getPluginCount(): number - Get total number of plugins
  • getPluginsInitializationStatus(): Record<string, {initialized: boolean; error?: string}> - Check plugin initialization status
  • getPluginsByCategory(category: PluginCategory): ShogunPlugin[] - Get plugins by category
  • validatePluginSystem(): {...} - Validate plugin system health
  • reinitializeFailedPlugins(): {...} - Reinitialize failed plugins
  • checkPluginCompatibility(): {...} - Check plugin compatibility
  • getPluginSystemDebugInfo(): {...} - Get comprehensive debug information
  • addPeer(peer: string): void - Add new peer to network
  • removePeer(peer: string): void - Remove peer from network
  • getCurrentPeers(): string[] - Get currently connected peers
  • getAllConfiguredPeers(): string[] - Get all configured peers
  • getPeerInfo(): {[peer: string]: {connected: boolean; status: string}} - Get detailed peer information
  • reconnectToPeer(peer: string): void - Reconnect to specific peer
  • resetPeers(newPeers?: string[]): void - Reset all peers and optionally add new ones
  • getUserByAlias(alias: string): Promise<{...}> - Get user by alias/username
  • getUserDataByPub(userPub: string): Promise<{...}> - Get user by public key
  • getUserPubByEpub(epub: string): Promise<string | null> - Get user public key by encryption key
  • getUserAliasByPub(userPub: string): Promise<string | null> - Get user alias by public key
  • getAllRegisteredUsers(): Promise<Array<{...}>> - Get all registered users
  • updateUserLastSeen(userPub: string): Promise<void> - Update user's last seen timestamp
  • setPasswordHintWithSecurity(username: string, password: string, hint: string, securityQuestions: string[], securityAnswers: string[]): Promise<{success: boolean; error?: string}> - Set up password recovery
  • forgotPassword(username: string, securityAnswers: string[]): Promise<{success: boolean; hint?: string; error?: string}> - Recover password
  • getRecentErrors(count?: number): ShogunError[] - Get recent errors for debugging
  • on<K extends keyof ShogunEventMap>(eventName: K, listener: Function): this - Subscribe to typed events
  • off<K extends keyof ShogunEventMap>(eventName: K, listener: Function): this - Unsubscribe from events
  • once<K extends keyof ShogunEventMap>(eventName: K, listener: Function): this - Subscribe to one-time events
  • emit<K extends keyof ShogunEventMap>(eventName: K, data?: ShogunEventMap[K]): boolean - Emit custom events
  • removeAllListeners(eventName?: string | symbol): this - Remove all event listeners
interface ShogunCoreConfig {
peers?: string[]; // GunDB peer URLs
scope?: string; // Application scope
authToken?: string; // GunDB super peer secret
appToken?: string; // Application token

// Plugin configurations
webauthn?: {
enabled?: boolean;
rpName?: string;
rpId?: string;
};

web3?: {
enabled?: boolean;
};

nostr?: {
enabled?: boolean;
};

zkproof?: {
enabled?: boolean;
defaultGroupId?: string;
deterministic?: boolean;
};

// Timeouts
timeouts?: {
login?: number;
signup?: number;
operation?: number;
};
}

Shogun Core provides a comprehensive typed event system for monitoring authentication and data changes:

// Available events with their data types
interface ShogunEventMap {
"auth:login": AuthEventData; // User logged in
"auth:logout": void; // User logged out
"auth:signup": AuthEventData; // New user registered
"plugin:registered": { name: string; version?: string; category?: string }; // Plugin registered
"plugin:unregistered": { name: string }; // Plugin unregistered
debug: { action: string; [key: string]: any }; // Debug information
error: ErrorEventData; // Error occurred
}

// Listen for authentication events with full type safety
shogun.on("auth:login", (data) => {
console.log("User logged in:", data.username);
console.log("Authentication method:", data.method);
if (data.provider) {
console.log("Provider:", data.provider);
}
});

shogun.on("auth:logout", () => {
console.log("User logged out");
});

shogun.on("auth:signup", (data) => {
console.log("New user signed up:", data.username);
});

// Listen for errors
shogun.on("error", (error) => {
console.error("Shogun error:", error.message);
});

Shogun Core includes a secure password recovery system using security questions:

// Set password hint with security questions
await shogun.db.setPasswordHint(
"username",
"password",
"My favorite color",
["What is your favorite color?", "What was your first pet's name?"],
["blue", "fluffy"]
);

// Recover password using security answers
const result = await shogun.db.forgotPassword("username", ["blue", "fluffy"]);

if (result.success) {
console.log("Password hint:", result.hint);
}

Note: The cryptographic wallet derivation feature has been removed in v1.9.5 to simplify the architecture.

Shogun Core includes comprehensive error handling with typed errors:

import { ShogunError, ErrorType } from "shogun-core";

try {
await shogun.login("username", "password");
} catch (error) {
if (error instanceof ShogunError) {
switch (error.type) {
case ErrorType.AUTHENTICATION:
console.error("Invalid credentials");
break;
case ErrorType.NETWORK:
console.error("Network connection failed");
break;
default:
console.error("Unknown error:", error.message);
}
}
}

We welcome contributions! Please see our Contributing Guide for details.

This project is licensed under the MIT License - see the LICENSE file for details.

Shogun Core implements SHIP standards - modular, composable protocols for decentralized applications:

  • SHIP-00: Identity & Authentication Foundation
  • SHIP-01: Decentralized Encrypted Messaging
  • SHIP-02: Ethereum HD Wallet & Transaction Sending
  • SHIP-03: Dual-Key Stealth Addresses (ERC-5564)
  • SHIP-04: Multi-Modal Authentication (WebAuthn/Web3/Nostr/ZK-Proof)

See ship/README.md for complete SHIP documentation and examples.

For advanced use cases and comprehensive API coverage, see the Advanced API Features section which includes:

  • Advanced Plugin Management: Plugin health monitoring, compatibility checking, and system validation
  • Peer Network Management: Dynamic peer connection management and network monitoring
  • Advanced User Management: Comprehensive user lookup, tracking, and metadata management
  • Password Recovery & Security: Secure password hint system with security questions
  • Error Handling & Debugging: Advanced error tracking and debugging capabilities
  • Event System: Complete event handling reference with type safety
  • Database Lifecycle: Advanced database initialization and management

SHOGUN CORE

Core library for Shogun Ecosystem

This project includes a comprehensive test suite that covers all major functionality and has been recently updated to align with the current codebase structure.

  • βœ… All Tests Passing: 696+ tests pass successfully
  • βœ… Plugin System: Complete plugin functionality testing
  • βœ… Authentication Methods: All auth methods (WebAuthn, Web3, Nostr, ZK-Proof) tested
  • βœ… Simple API: Full coverage of SimpleGunAPI functionality
  • βœ… Error Handling: Comprehensive error handling and edge case testing
  • βœ… Browser Compatibility: Cross-browser support validation
  • βœ… Integration Tests: End-to-end functionality testing

This project includes a comprehensive test suite that covers:

  • Validation Utils (src/__tests__/utils/validation.test.ts)

    • Username validation
    • Email validation
    • Username generation from identity
    • Deterministic password generation
  • Error Handler (src/__tests__/utils/errorHandler.test.ts)

    • Error creation and handling
    • Error statistics and logging
    • Retry logic
    • External logger integration
  • Event Emitter (src/__tests__/utils/eventEmitter.test.ts)

    • Event registration and emission
    • Listener management
    • Error handling in listeners
    • Symbol events support
  • Storage (src/__tests__/storage/storage.test.ts)

    • Memory and localStorage operations
    • Error handling
    • Test mode behavior
    • Data persistence
  • ShogunCore (src/__tests__/integration/shogunCore.test.ts)
    • Plugin system validation
    • Authentication methods
    • Event system
    • Configuration handling
    • Error handling
  • Compatibility (src/__tests__/browser/compatibility.test.ts)
    • localStorage availability
    • Crypto API support
    • WebAuthn detection
    • Web3 provider detection
    • Event system compatibility
    • TextEncoder/TextDecoder support
    • Fetch API compatibility
    • URL API compatibility
    • Performance API compatibility
    • Console API compatibility

You can eseguire i test sia dalla root del monorepo sia entrando nella cartella shogun-core.

Inside shogun-core/ directory:

# Install deps
yarn install

# Tutti i test (una sola esecuzione) con coverage
yarn test:ci

# Watch mode
yarn test:watch

# Coverage (report HTML in coverage/lcov-report/index.html)
yarn coverage

# Solo i test dei plugin
yarn test src/__tests__/plugins

# Evita conflitti di config Jest (se servisse)
yarn jest --ci --coverage --watchAll=false --config jest.config.js

From repository root (senza cambiare directory):

# Install deps
yarn --cwd shogun-core install

# Tutti i test con coverage (CI‑like)
yarn --cwd shogun-core test:ci

# Solo plugin tests
yarn --cwd shogun-core test src/__tests__/plugins

# Coverage
yarn --cwd shogun-core coverage

# Watch mode
yarn --cwd shogun-core test:watch

# Se compaiono piΓΉ configurazioni Jest, specifica esplicitamente il config file
yarn --cwd shogun-core jest --ci --coverage --watchAll=false --config jest.config.js

CI & QA scripts:

# Mutation testing (Stryker) – piΓΉ lento, richiede devDeps installate
yarn --cwd shogun-core mutation

# SAST (Semgrep) – richiede semgrep installato (es. `pip install semgrep`)
yarn --cwd shogun-core sast

The test suite provides comprehensive coverage of:

  • βœ… Utility Functions - 100% coverage
  • βœ… Error Handling - 100% coverage
  • βœ… Event System - 100% coverage
  • βœ… Storage Operations - 100% coverage
  • βœ… Plugin System - API validation
  • βœ… Browser Compatibility - Cross-browser support
  • βœ… Configuration Validation - Config handling

These tests are designed to be realistic and non-intrusive:

  • No codebase modifications - Tests work with existing code
  • Comprehensive coverage - All public APIs tested
  • Error resilience - Tests error handling and edge cases
  • Browser compatibility - Cross-browser support validation
  • Performance aware - Tests don't impact runtime performance
src/__tests__/
β”œβ”€β”€ setup.ts # Global test setup
β”œβ”€β”€ utils/
β”‚ β”œβ”€β”€ validation.test.ts # Validation utility tests
β”‚ β”œβ”€β”€ errorHandler.test.ts # Error handling tests
β”‚ └── eventEmitter.test.ts # Event system tests
β”œβ”€β”€ storage/
β”‚ └── storage.test.ts # Storage operation tests
β”œβ”€β”€ integration/
β”‚ └── shogunCore.test.ts # Core integration tests
└── browser/
└── compatibility.test.ts # Browser compatibility tests

When adding new tests:

  1. Follow the existing test structure
  2. Use descriptive test names
  3. Test both success and failure cases
  4. Mock external dependencies appropriately
  5. Ensure tests are isolated and repeatable