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.
remove() and removeUserData() methods that was causing TypeError: Cannot read properties of null (reading 'err')SimpleGunAPI to focus on high-level helpers only
api.database for basic operations (get, put, auth, etc.)quickStart(), autoQuickStart() classes for rapid initializationany usage with better TypeScript typesFixed Critical Remove Operations Bug:
TypeError: Cannot read properties of null (reading 'err') in remove() and removeUserData() methodsack && ack.err instead of just ack.errputUserArray(), getUserArray(), addToUserArray(), removeFromUserArray(), updateInUserArray() have been REMOVED due to GunDB compatibility issuesputArray(), getArray(), addToArray(), removeFromArray(), updateInArray() are deprecated and show warningsAuthResult and SignUpResult typeslogin() and signUp() interfacesnpm 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);
api.database or shogun.database for direct Gun operationsapi helper methods for standardized data - profile, settings, collectionsusers/alice/profileShogun 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:
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:
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:
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>
);
}
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 accountlogin(username: string, password: string): Promise<UserInfo | null> - Authenticate with username/passwordlogout(): void - Logout current userisLoggedIn(): boolean - Check if user is authenticatedget<T>(path: string): Promise<T | null> - Get data from pathput<T>(path: string, data: T): Promise<boolean> - Store data at pathset<T>(path: string, data: T): Promise<boolean> - Update data at pathremove(path: string): Promise<boolean> - Remove data from pathnode(path: string): GunNode - Get Gun node for direct chaining (recommended)chain(path: string): ChainingWrapper - Get simplified chaining wrappergetNode(path: string): GunNode - Get Gun node for advanced operations like .map()putUserData<T>(path: string, data: T): Promise<boolean> - Store user-specific datagetUserData<T>(path: string): Promise<T | null> - Get user-specific datasetUserData<T>(path: string, data: T): Promise<boolean> - Update user-specific dataremoveUserData(path: string): Promise<boolean> - Remove user-specific datagetAllUserData(): Promise<Record<string, unknown> | null> - Get all user dataupdateProfile(profileData: ProfileData): Promise<boolean> - Update user profilegetProfile(): Promise<Record<string, unknown> | null> - Get user profilesaveSettings(settings: Record<string, unknown>): Promise<boolean> - Save user settingsgetSettings(): Promise<Record<string, unknown> | null> - Get user settingssavePreferences(preferences: Record<string, unknown>): Promise<boolean> - Save user preferencesgetPreferences(): Promise<Record<string, unknown> | null> - Get user preferencescreateCollection<T>(name: string, items: Record<string, T>): Promise<boolean> - Create user collectionaddToCollection<T>(name: string, itemId: string, item: T): Promise<boolean> - Add item to collectiongetCollection(name: string): Promise<Record<string, unknown> | null> - Get collectionremoveFromCollection(name: string, itemId: string): Promise<boolean> - Remove item from collectionarrayToIndexedObject<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/passwordloginWithPair(pair: ISEAPair): Promise<AuthResult> - Authenticate directly with a GunDB SEA pairsignUp(username: string, password: string, email?: string, pair?: ISEAPair | null): Promise<SignUpResult> - Create new user accountlogout(): void - Logout current userisLoggedIn(): boolean - Check if user is authenticatedsetAuthMethod(method: AuthMethod): void - Set authentication methodgetAuthMethod(): AuthMethod | undefined - Get current authentication methodsaveCredentials(credentials: any): Promise<void> - Save user credentialsgetPlugin<T>(name: string): T | undefined - Get plugin by namehasPlugin(name: string): boolean - Check if plugin existsregister(plugin: ShogunPlugin): void - Register custom pluginunregister(pluginName: string): void - Remove plugingetPluginsInfo(): Array<{name: string; version: string; category?: PluginCategory; description?: string}> - Get detailed plugin informationgetPluginCount(): number - Get total number of pluginsgetPluginsInitializationStatus(): Record<string, {initialized: boolean; error?: string}> - Check plugin initialization statusgetPluginsByCategory(category: PluginCategory): ShogunPlugin[] - Get plugins by categoryvalidatePluginSystem(): {...} - Validate plugin system healthreinitializeFailedPlugins(): {...} - Reinitialize failed pluginscheckPluginCompatibility(): {...} - Check plugin compatibilitygetPluginSystemDebugInfo(): {...} - Get comprehensive debug informationaddPeer(peer: string): void - Add new peer to networkremovePeer(peer: string): void - Remove peer from networkgetCurrentPeers(): string[] - Get currently connected peersgetAllConfiguredPeers(): string[] - Get all configured peersgetPeerInfo(): {[peer: string]: {connected: boolean; status: string}} - Get detailed peer informationreconnectToPeer(peer: string): void - Reconnect to specific peerresetPeers(newPeers?: string[]): void - Reset all peers and optionally add new onesgetUserByAlias(alias: string): Promise<{...}> - Get user by alias/usernamegetUserDataByPub(userPub: string): Promise<{...}> - Get user by public keygetUserPubByEpub(epub: string): Promise<string | null> - Get user public key by encryption keygetUserAliasByPub(userPub: string): Promise<string | null> - Get user alias by public keygetAllRegisteredUsers(): Promise<Array<{...}>> - Get all registered usersupdateUserLastSeen(userPub: string): Promise<void> - Update user's last seen timestampsetPasswordHintWithSecurity(username: string, password: string, hint: string, securityQuestions: string[], securityAnswers: string[]): Promise<{success: boolean; error?: string}> - Set up password recoveryforgotPassword(username: string, securityAnswers: string[]): Promise<{success: boolean; hint?: string; error?: string}> - Recover passwordgetRecentErrors(count?: number): ShogunError[] - Get recent errors for debuggingon<K extends keyof ShogunEventMap>(eventName: K, listener: Function): this - Subscribe to typed eventsoff<K extends keyof ShogunEventMap>(eventName: K, listener: Function): this - Unsubscribe from eventsonce<K extends keyof ShogunEventMap>(eventName: K, listener: Function): this - Subscribe to one-time eventsemit<K extends keyof ShogunEventMap>(eventName: K, data?: ShogunEventMap[K]): boolean - Emit custom eventsremoveAllListeners(eventName?: string | symbol): this - Remove all event listenersinterface 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:
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:
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.
This project includes a comprehensive test suite that covers:
Validation Utils (src/__tests__/utils/validation.test.ts)
Error Handler (src/__tests__/utils/errorHandler.test.ts)
Event Emitter (src/__tests__/utils/eventEmitter.test.ts)
Storage (src/__tests__/storage/storage.test.ts)
src/__tests__/integration/shogunCore.test.ts)
src/__tests__/browser/compatibility.test.ts)
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:
These tests are designed to be realistic and non-intrusive:
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: