Shogun Core is a comprehensive SDK for building decentralized applications (dApps) that simplifies authentication, wallet management, and decentralized data storage. It combines GunDB's or Holster's peer-to-peer networking with modern authentication standards and blockchain integration.
Now supports both Gun and Holster! You can use either database backend - Gun for maximum compatibility or Holster for modern ES modules and improved performance.
- π Multiple Authentication Methods: Password, WebAuthn (biometrics), Web3 (MetaMask), Nostr, ZK-Proof (anonymous)
- π Decentralized Storage: Built on GunDB or Holster for peer-to-peer data synchronization
- π Dual Database Support: Use Gun (maximum compatibility) or Holster (modern ES modules, improved performance)
- π Plugin System: Extensible architecture with built-in plugins
- πΌ Smart Wallet: Account Abstraction 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
npm install shogun-core
# or
yarn add shogun-coreimport { ShogunCore } from "shogun-core";
import Gun from "gun";
// Create Gun instance first
const gun = Gun({
peers: ['https://gun-manhattan.herokuapp.com/gun']
});
// Initialize Shogun Core with the Gun instance
const shogun = new ShogunCore({
gunInstance: gun,
// Enable authentication plugins
web3: { enabled: true },
webauthn: {
enabled: true,
rpName: "My Awesome App",
rpId: window.location.hostname,
},
nostr: { enabled: true },
zkproof: {
enabled: true,
defaultGroupId: "my-app-users",
},
});
// Register Smart Wallet plugin separately if needed
import { SmartWalletPlugin } from "shogun-core";
const smartWalletPlugin = new SmartWalletPlugin({
enabled: true,
factoryAddress: "0x...",
defaultRequiredSignatures: 1,
defaultRequiredGuardians: 2,
});
shogun.register(smartWalletPlugin);import { ShogunCore } from "shogun-core";
import Holster from "@mblaney/holster";
// Create Holster instance first
const holster = Holster({
peers: ['ws://localhost:8765']
});
// Initialize Shogun Core with the Holster instance
const shogun = new ShogunCore({
holsterInstance: holster, // Use Holster instead of Gun
// Enable authentication plugins (same as Gun)
web3: { enabled: true },
webauthn: {
enabled: true,
rpName: "My Awesome App",
rpId: window.location.hostname,
},
nostr: { enabled: true },
zkproof: {
enabled: true,
defaultGroupId: "my-app-users",
},
});
// All other APIs work the same way!const db = shogun.db;
// Store data using Gun chaining
await db.get('users').get('alice').get('profile').put({
name: 'Alice Smith',
email: 'alice@example.com'
});
// Read 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('name').put('Alice Johnson');
// Iterate over collections with .map()
db.get('users').map((user, userId) => {
console.log(`User ${userId}:`, user);
});// Sign up
const signUpResult = await shogun.signUp("username", "password");
if (signUpResult.success) {
console.log("User created:", signUpResult.username);
}
// Login
const loginResult = await shogun.login("username", "password");
if (loginResult.success) {
console.log("Logged in as:", loginResult.username);
}const web3Plugin = shogun.getPlugin("web3");
if (web3Plugin && web3Plugin.isAvailable()) {
const connectionResult = await web3Plugin.connectMetaMask();
if (connectionResult.success) {
const address = connectionResult.address!;
// Login with Web3 wallet
const loginResult = await web3Plugin.login(address);
if (loginResult.success) {
console.log("Web3 login successful");
}
// Register new user
const signUpResult = await web3Plugin.signUp(address);
if (signUpResult.success) {
console.log("Web3 registration successful");
}
}
}const webauthnPlugin = shogun.getPlugin("webauthn");
if (webauthnPlugin && webauthnPlugin.isSupported()) {
// Register with seed phrase for multi-device support
const signUpResult = await webauthnPlugin.signUp("username", {
generateSeedPhrase: true
});
if (signUpResult.success && signUpResult.seedPhrase) {
console.log("π SAVE THESE 12 WORDS:", signUpResult.seedPhrase);
}
// Import account on another device
const importResult = await webauthnPlugin.importFromSeed(
"username",
"word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12"
);
// Authenticate
const loginResult = await webauthnPlugin.login("username");
if (loginResult.success) {
console.log("WebAuthn authentication successful");
}
}const nostrPlugin = shogun.getPlugin("nostr");
if (nostrPlugin && nostrPlugin.isAvailable()) {
const connectionResult = await nostrPlugin.connectNostrWallet();
if (connectionResult.success) {
const address = connectionResult.address!;
const loginResult = await nostrPlugin.login(address);
if (loginResult.success) {
console.log("Nostr login successful");
}
const signUpResult = await nostrPlugin.signUp(address);
if (signUpResult.success) {
console.log("Nostr registration successful");
}
}
}const zkPlugin = shogun.getPlugin("zkproof");
if (zkPlugin && zkPlugin.isAvailable()) {
// Sign up with ZK-Proof (creates anonymous identity)
const signUpResult = await zkPlugin.signUp();
if (signUpResult.success && signUpResult.seedPhrase) {
console.log("π SAVE THIS TRAPDOOR:", signUpResult.seedPhrase);
}
// Login with trapdoor (anonymous authentication)
const loginResult = await zkPlugin.login(trapdoor);
if (loginResult.success) {
console.log("ZK-Proof login successful (anonymous)");
}
}import { SmartWalletPlugin } from "shogun-core";
// Register Smart Wallet plugin
const smartWalletPlugin = new SmartWalletPlugin({
enabled: true,
factoryAddress: "0x...", // Smart Wallet Factory contract address
defaultRequiredSignatures: 1,
defaultRequiredGuardians: 2,
});
shogun.register(smartWalletPlugin);
// Configure signer (derive EOA from WebAuthn seed phrase)
const webauthnPlugin = shogun.getPlugin("webauthn");
const signUpResult = await webauthnPlugin.signUp("alice", {
generateSeedPhrase: true
});
import { derive } from "shogun-core";
const wallet = await derive(signUpResult.seedPhrase!, "alice", {
includeSecp256k1Ethereum: true
});
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);
}<!DOCTYPE html>
<html>
<head>
<title>Shogun Core in Browser</title>
</head>
<body>
<h1>My dApp</h1>
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gun/sea.js"></script>
<script src="https://cdn.jsdelivr.net/npm/shogun-core/dist/browser/shogun-core.js"></script>
<script>
// Create Gun instance first
const gun = Gun({
peers: ["https://gun-manhattan.herokuapp.com/gun"]
});
// Initialize Shogun Core
const shogunCore = new window.SHOGUN_CORE({
gunInstance: gun,
web3: { enabled: true },
webauthn: {
enabled: true,
rpName: "My Browser dApp",
rpId: window.location.hostname,
},
});
console.log("Shogun Core initialized in browser!", shogunCore);
</script>
</body>
</html><!DOCTYPE html>
<html>
<head>
<title>Shogun Core with Holster</title>
</head>
<body>
<h1>My dApp</h1>
<script type="module">
import Holster from 'https://cdn.jsdelivr.net/npm/@mblaney/holster/build/holster.js';
import { ShogunCore } from 'https://cdn.jsdelivr.net/npm/shogun-core/dist/src/index.js';
// Create Holster instance
const holster = Holster({
peers: ['ws://localhost:8765']
});
// Initialize Shogun Core
const shogunCore = new ShogunCore({
holsterInstance: holster,
web3: { enabled: true },
webauthn: {
enabled: true,
rpName: "My Browser dApp",
rpId: window.location.hostname,
},
});
console.log("Shogun Core initialized with Holster!", shogunCore);
</script>
</body>
</html>// Listen for authentication events
shogun.on("auth:login", (data) => {
console.log("User logged in:", data.username);
console.log("Authentication method:", data.method);
});
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 supports both Gun and Holster as database backends. Choose based on your needs:
- Pros: Maximum compatibility, large ecosystem, battle-tested
- Cons: Older codebase, CommonJS modules
- Best for: Existing projects, maximum compatibility
- Pros: Modern ES modules, improved performance, cleaner API
- Cons: Newer project, smaller ecosystem
- Best for: New projects, modern build systems, performance-critical apps
Note: The API is identical regardless of which backend you choose. Shogun Core handles all the differences internally.
- Pair-based authentication: Currently only supported with Gun (username/password works with both)
- Event system: Gun has native events, Holster uses polling (handled automatically)
- Chaining API: Gun uses
.get().get(), Holster uses.get().next()(handled automatically via proxy)
interface ShogunCoreConfig {
gunInstance?: IGunInstance<any>; // Optional: existing Gun instance (required if holsterInstance not provided)
holsterInstance?: any; // Optional: existing Holster instance (required if gunInstance not provided)
// Plugin configurations
webauthn?: {
enabled?: boolean;
rpName?: string;
rpId?: string;
};
web3?: {
enabled?: boolean;
};
nostr?: {
enabled?: boolean;
};
zkproof?: {
enabled?: boolean;
defaultGroupId?: string;
deterministic?: boolean;
minEntropy?: number;
};
postAuth?: {
enabled?: boolean;
};
// Timeouts
timeouts?: {
login?: number;
signup?: number;
operation?: number;
};
plugins?: {
autoRegister?: ShogunPlugin[];
};
disableAutoRecall?: boolean; // Disable automatic session recall on init
silent?: boolean; // Disable console logs
}Note:
- Either
gunInstanceorholsterInstancemust be provided (but not both) SmartWalletPluginmust be registered separately usingshogun.register()as it's not included in the main configuration
If you're currently using Gun and want to switch to Holster:
-
Install Holster:
npm install @mblaney/holster # or yarn add @mblaney/holster -
Update your initialization:
// Before (Gun) import Gun from "gun"; const gun = Gun({ peers: [...] }); const shogun = new ShogunCore({ gunInstance: gun }); // After (Holster) import Holster from "@mblaney/holster"; const holster = Holster({ peers: [...] }); const shogun = new ShogunCore({ holsterInstance: holster });
-
That's it! All other code remains the same. The API is identical.
- Pair-based authentication (
loginWithPair()) is not yet supported - use username/password instead - Some advanced Gun features may not be available
- Event system uses polling instead of native events (handled automatically)
# Install dependencies
yarn install
# Run all tests with coverage
yarn test:ci
# Watch mode
yarn test:watch
# Coverage report
yarn coverage
# Plugin tests only
yarn test src/__tests__/plugins- π Documentation
- π¬ Telegram Community
- π Issue Tracker
This project is licensed under the MIT License - see the LICENSE file for details.