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.
handleSimpleOAuth
and Alby supportupdateUserAlias
(use changeUsername
instead)clearAllStorageData
, exportPair
AuthResult
and SignUpResult
typeslogin()
and signUp()
interfacesnpm install shogun-core
# or
yarn add shogun-core
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 OAuth providers
oauth: {
enabled: true,
usePKCE: true, // Recommended for SPAs
providers: {
google: {
clientId: "YOUR_GOOGLE_CLIENT_ID",
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET", // For server-side flow
redirectUri: "http://localhost:3000/auth/callback",
scope: ["openid", "email", "profile"],
},
},
},
});
// Initialize the SDK
await shogun.initialize();
console.log("Shogun Core initialized!");
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;
};
// OAuth-specific properties
redirectUrl?: string; // OAuth redirect URL
pendingAuth?: boolean; // Indicates pending OAuth flow
message?: string; // Status message
provider?: string; // OAuth provider name
isNewUser?: boolean; // True if this was a registration
user?: {
// OAuth user data
userPub?: string;
username?: string;
email?: string;
name?: string;
picture?: string;
oauth?: {
provider: string;
id: string;
email?: string;
name?: string;
picture?: string;
lastLogin: number;
};
};
}
// 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
// OAuth flow support - β
ADDED
redirectUrl?: string;
pendingAuth?: boolean;
provider?: string;
user?: OAuthUserInfo; // β
ADDED
}
// Supported authentication methods
type AuthMethod =
| "password"
| "webauthn"
| "web3"
| "nostr"
| "oauth"
| "bitcoin"
| "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:
const webauthnPlugin = shogun.getPlugin<WebauthnPlugin>("webauthn");
if (webauthnPlugin && webauthnPlugin.isSupported()) {
// Register new user with WebAuthn - Returns SignUpResult β
const signUpResult: SignUpResult = await webauthnPlugin.signUp("username");
if (signUpResult.success) {
console.log("WebAuthn registration successful");
console.log("User public key:", signUpResult.userPub);
}
// 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>;
}
Social login with external providers (Google, GitHub, etc.):
const oauthPlugin = shogun.getPlugin<OAuthPlugin>("oauth");
if (oauthPlugin && oauthPlugin.isSupported()) {
// Get available providers
const providers = oauthPlugin.getAvailableProviders(); // ["google", "github", ...]
// Initiate signup with OAuth - Returns SignUpResult with redirect β
const signUpResult: SignUpResult = await oauthPlugin.signUp("google");
if (signUpResult.success && signUpResult.redirectUrl) {
// Redirect user to OAuth provider
window.location.href = signUpResult.redirectUrl;
}
// Handle OAuth callback (after redirect back from provider) - Returns AuthResult β
const callbackResult: AuthResult = await oauthPlugin.handleOAuthCallback(
"google",
authCode, // From URL params
state // From URL params
);
if (callbackResult.success) {
console.log("OAuth authentication successful");
if (callbackResult.user) {
console.log("User email:", callbackResult.user.email);
console.log("User name:", callbackResult.user.name);
}
}
}
// Plugin Interface - β
FIXED TYPES
interface OAuthPluginInterface {
// Authentication methods
login(provider: OAuthProvider): Promise<AuthResult>; // β
CORRECT
signUp(provider: OAuthProvider): Promise<SignUpResult>; // β
FIXED
// OAuth flow management
isSupported(): boolean;
getAvailableProviders(): OAuthProvider[];
initiateOAuth(provider: OAuthProvider): Promise<OAuthConnectionResult>;
completeOAuth(
provider: OAuthProvider,
authCode: string,
state?: string
): Promise<OAuthConnectionResult>;
handleOAuthCallback(
provider: OAuthProvider,
authCode: string,
state: string
): Promise<AuthResult>;
// Credential management
generateCredentials(
userInfo: OAuthUserInfo,
provider: OAuthProvider
): Promise<OAuthCredentials>;
}
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>
// The script exposes a global `initShogun` function
const shogun = initShogun({
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!", shogun);
async function connectWallet() {
if (shogun.hasPlugin("web3")) {
const web3Plugin = shogun.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>
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 authenticatedgetPlugin<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 pluginon<K extends keyof ShogunEventMap>(eventName: K, listener: Function): this
- Subscribe to typed eventsoff<K extends keyof ShogunEventMap>(eventName: K, listener: Function): this
- Unsubscribe from eventsemit<K extends keyof ShogunEventMap>(eventName: K, data?: ShogunEventMap[K]): boolean
- Emit custom eventsinterface ShogunSDKConfig {
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;
};
oauth?: {
enabled?: boolean;
usePKCE?: boolean;
providers?: Record<string, any>;
};
// 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
"wallet:created": WalletEventData; // Wallet derived from user keys
"gun:put": GunDataEventData; // Data written to GunDB
"gun:get": GunDataEventData; // Data read from GunDB
"gun:set": GunDataEventData; // Data updated in GunDB
"gun:remove": GunDataEventData; // Data removed from GunDB
"gun:peer:add": GunPeerEventData; // Peer added
"gun:peer:remove": GunPeerEventData; // Peer removed
"gun:peer:connect": GunPeerEventData; // Peer connected
"gun:peer:disconnect": GunPeerEventData; // Peer disconnected
"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("OAuth 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);
});
// Nota: in v1.7.0 l'evento `wallet:created` non Γ¨ emesso dal core
// Listen for errors
shogun.on("error", (error) => {
console.error("Shogun error:", error.message);
});
Nota: la derivazione automatica dei wallet e l'evento wallet:created
sono sperimentali e non garantiti in v1.7.0.
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.
Core library for Shogun Ecosystem
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: