shogun-core
Version:
SHOGUN CORE - Core library for Shogun Ecosystem
967 lines (966 loc) • 36.5 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ShogunCore = exports.GunInstance = exports.GunErrors = exports.derive = exports.crypto = exports.GunRxJS = exports.Gun = exports.SEA = void 0;
const events_1 = require("./types/events");
const errorHandler_1 = require("./utils/errorHandler");
const storage_1 = require("./storage/storage");
const shogun_1 = require("./types/shogun");
const webauthnPlugin_1 = require("./plugins/webauthn/webauthnPlugin");
const web3ConnectorPlugin_1 = require("./plugins/web3/web3ConnectorPlugin");
const nostrConnectorPlugin_1 = require("./plugins/nostr/nostrConnectorPlugin");
const oauthPlugin_1 = require("./plugins/oauth/oauthPlugin");
const gundb_1 = require("./gundb");
Object.defineProperty(exports, "Gun", { enumerable: true, get: function () { return gundb_1.Gun; } });
Object.defineProperty(exports, "SEA", { enumerable: true, get: function () { return gundb_1.SEA; } });
Object.defineProperty(exports, "GunInstance", { enumerable: true, get: function () { return gundb_1.GunInstance; } });
Object.defineProperty(exports, "GunRxJS", { enumerable: true, get: function () { return gundb_1.GunRxJS; } });
Object.defineProperty(exports, "crypto", { enumerable: true, get: function () { return gundb_1.crypto; } });
Object.defineProperty(exports, "derive", { enumerable: true, get: function () { return gundb_1.derive; } });
Object.defineProperty(exports, "GunErrors", { enumerable: true, get: function () { return gundb_1.GunErrors; } });
__exportStar(require("./utils/errorHandler"), exports);
__exportStar(require("./plugins"), exports);
__exportStar(require("./types/shogun"), exports);
/**
* Main ShogunCore class - implements the IShogunCore interface
*
* This is the primary entry point for the Shogun SDK, providing access to:
* - Decentralized database (GunInstance)
* - Authentication methods (traditional, WebAuthn, MetaMask)
* - Plugin system for extensibility
* - RxJS integration for reactive programming
*
* @since 2.0.0
*/
class ShogunCore {
static API_VERSION = "^1.6.6";
db;
storage;
provider;
config;
rx;
_gun;
_user = null;
eventEmitter;
plugins = new Map();
currentAuthMethod;
wallets;
/**
* Initialize the Shogun SDK
* @param config - SDK Configuration object
* @description Creates a new instance of ShogunCore with the provided configuration.
* Initializes all required components including storage, event emitter, GunInstance connection,
* and plugin system.
*/
constructor(config) {
// Polyfill console for environments where it might be missing
if (typeof console === "undefined") {
global.console = {
log: () => { },
warn: () => { },
error: () => { },
info: () => { },
debug: () => { },
};
}
this.config = config;
this.storage = new storage_1.ShogunStorage();
this.eventEmitter = new events_1.ShogunEventEmitter();
errorHandler_1.ErrorHandler.addListener((error) => {
this.eventEmitter.emit("error", {
action: error.code,
message: error.message,
type: error.type,
});
});
if (config.authToken) {
(0, gundb_1.restrictedPut)(gundb_1.Gun, config.authToken);
}
try {
if (config.gunInstance) {
this._gun = config.gunInstance;
}
else {
this._gun = (0, gundb_1.Gun)({
peers: config.peers || [],
radisk: false,
localStorage: false,
});
}
}
catch (error) {
if (typeof console !== "undefined" && console.error) {
console.error("Error creating Gun instance:", error);
}
throw new Error(`Failed to create Gun instance: ${error}`);
}
try {
this.db = new gundb_1.GunInstance(this._gun, config.scope || "");
this._gun = this.db.gun;
this.setupGunEventForwarding();
}
catch (error) {
if (typeof console !== "undefined" && console.error) {
console.error("Error initializing GunInstance:", error);
}
throw new Error(`Failed to initialize GunInstance: ${error}`);
}
try {
this._user = this._gun.user().recall({ sessionStorage: true });
}
catch (error) {
if (typeof console !== "undefined" && console.error) {
console.error("Error initializing Gun user:", error);
}
throw new Error(`Failed to initialize Gun user: ${error}`);
}
this._gun.on("auth", (user) => {
this._user = this._gun.user().recall({ sessionStorage: true });
this.eventEmitter.emit("auth:login", {
userPub: user.pub,
method: "password",
});
});
this.rx = new gundb_1.GunRxJS(this._gun);
this.registerBuiltinPlugins(config);
// Initialize async components
this.initialize().catch((error) => {
if (typeof console !== "undefined" && console.warn) {
console.warn("Error during async initialization:", error);
}
});
}
/**
* Initialize the Shogun SDK asynchronously
* This method handles initialization tasks that require async operations
*/
async initialize() {
try {
await this.db.initialize();
this.eventEmitter.emit("debug", {
action: "core_initialized",
timestamp: Date.now(),
});
}
catch (error) {
if (typeof console !== "undefined" && console.error) {
console.error("Error during Shogun Core initialization:", error);
}
throw error;
}
}
/**
* Access to the Gun instance
* @returns The Gun instance
*/
get gun() {
return this._gun;
}
/**
* Access to the current user
* @returns The current Gun user instance
*/
get user() {
return this._user;
}
/**
* Gets the current user information
* @returns Current user object or null
*/
getCurrentUser() {
if (!this.db) {
return null;
}
return this.db.getCurrentUser();
}
/**
* Setup event forwarding from GunInstance to main event emitter
* @private
*/
setupGunEventForwarding() {
const gunEvents = ["gun:put", "gun:get", "gun:set", "gun:remove"];
gunEvents.forEach((eventName) => {
this.db.on(eventName, (data) => {
this.eventEmitter.emit(eventName, data);
});
});
const peerEvents = [
"gun:peer:add",
"gun:peer:remove",
"gun:peer:connect",
"gun:peer:disconnect",
];
peerEvents.forEach((eventName) => {
this.db.on(eventName, (data) => {
this.eventEmitter.emit(eventName, data);
});
});
}
/**
* Register built-in plugins based on configuration
* @private
*/
registerBuiltinPlugins(config) {
try {
// Register OAuth plugin if configuration is provided
if (config.oauth) {
if (typeof console !== "undefined" && console.warn) {
console.warn("OAuth plugin will be registered with provided configuration");
}
const oauthPlugin = new oauthPlugin_1.OAuthPlugin();
if (typeof oauthPlugin.configure === "function") {
oauthPlugin.configure(config.oauth);
}
this.registerPlugin(oauthPlugin);
}
// Register WebAuthn plugin if configuration is provided
if (config.webauthn) {
if (typeof console !== "undefined" && console.warn) {
console.warn("WebAuthn plugin will be registered with provided configuration");
}
const webauthnPlugin = new webauthnPlugin_1.WebauthnPlugin();
if (typeof webauthnPlugin.configure === "function") {
webauthnPlugin.configure(config.webauthn);
}
this.registerPlugin(webauthnPlugin);
}
// Register Web3 plugin if configuration is provided
if (config.web3) {
if (typeof console !== "undefined" && console.warn) {
console.warn("Web3 plugin will be registered with provided configuration");
}
const web3Plugin = new web3ConnectorPlugin_1.Web3ConnectorPlugin();
if (typeof web3Plugin.configure === "function") {
web3Plugin.configure(config.web3);
}
this.registerPlugin(web3Plugin);
}
// Register Nostr plugin if configuration is provided
if (config.nostr) {
if (typeof console !== "undefined" && console.warn) {
console.warn("Nostr plugin will be registered with provided configuration");
}
const nostrPlugin = new nostrConnectorPlugin_1.NostrConnectorPlugin();
if (typeof nostrPlugin.configure === "function") {
nostrPlugin.configure(config.nostr);
}
this.registerPlugin(nostrPlugin);
}
}
catch (error) {
if (typeof console !== "undefined" && console.error) {
console.error("Error registering builtin plugins:", error);
}
}
}
/**
* Registers a plugin with the Shogun SDK
* @param plugin Plugin instance to register
* @throws Error if a plugin with the same name is already registered
*/
register(plugin) {
this.registerPlugin(plugin);
}
/**
* Unregisters a plugin from the Shogun SDK
* @param pluginName Name of the plugin to unregister
*/
unregister(pluginName) {
this.unregisterPlugin(pluginName);
}
/**
* Internal method to register a plugin
* @param plugin Plugin instance to register
*/
registerPlugin(plugin) {
try {
if (!plugin.name) {
if (typeof console !== "undefined" && console.error) {
console.error("Plugin registration failed: Plugin must have a name");
}
return;
}
if (this.plugins.has(plugin.name)) {
if (typeof console !== "undefined" && console.warn) {
console.warn(`Plugin "${plugin.name}" is already registered. Skipping.`);
}
return;
}
// Initialize plugin with core instance
plugin.initialize(this);
this.plugins.set(plugin.name, plugin);
this.eventEmitter.emit("plugin:registered", {
name: plugin.name,
version: plugin.version || "unknown",
category: plugin._category || "unknown",
});
}
catch (error) {
if (typeof console !== "undefined" && console.error) {
console.error(`Error registering plugin "${plugin.name}":`, error);
}
}
}
/**
* Internal method to unregister a plugin
* @param name Name of the plugin to unregister
*/
unregisterPlugin(name) {
try {
const plugin = this.plugins.get(name);
if (!plugin) {
if (typeof console !== "undefined" && console.warn) {
console.warn(`Plugin "${name}" not found for unregistration`);
}
return false;
}
// Destroy plugin if it has a destroy method
if (typeof plugin.destroy === "function") {
try {
plugin.destroy();
}
catch (destroyError) {
if (typeof console !== "undefined" && console.error) {
console.error(`Error destroying plugin "${name}":`, destroyError);
}
}
}
this.plugins.delete(name);
this.eventEmitter.emit("plugin:unregistered", {
name: plugin.name,
});
return true;
}
catch (error) {
if (typeof console !== "undefined" && console.error) {
console.error(`Error unregistering plugin "${name}":`, error);
}
return false;
}
}
/**
* Retrieve a registered plugin by name
* @param name Name of the plugin
* @returns The requested plugin or undefined if not found
* @template T Type of the plugin or its public interface
*/
getPlugin(name) {
if (!name || typeof name !== "string") {
if (typeof console !== "undefined" && console.warn) {
console.warn("Invalid plugin name provided to getPlugin");
}
return undefined;
}
const plugin = this.plugins.get(name);
if (!plugin) {
if (typeof console !== "undefined" && console.warn) {
console.warn(`Plugin "${name}" not found`);
}
return undefined;
}
return plugin;
}
/**
* Get information about all registered plugins
* @returns Array of plugin information objects
*/
getPluginsInfo() {
const pluginsInfo = [];
this.plugins.forEach((plugin) => {
pluginsInfo.push({
name: plugin.name,
version: plugin.version || "unknown",
category: plugin._category,
description: plugin.description,
});
});
return pluginsInfo;
}
/**
* Get the total number of registered plugins
* @returns Number of registered plugins
*/
getPluginCount() {
return this.plugins.size;
}
/**
* Check if all plugins are properly initialized
* @returns Object with initialization status for each plugin
*/
getPluginsInitializationStatus() {
const status = {};
this.plugins.forEach((plugin, name) => {
try {
// Verifica se il plugin ha un metodo per controllare l'inizializzazione
if (typeof plugin.assertInitialized === "function") {
plugin.assertInitialized();
status[name] = { initialized: true };
}
else {
// Fallback: verifica se il plugin ha un riferimento al core
status[name] = {
initialized: !!plugin.core,
error: !plugin.core
? "No core reference found"
: undefined,
};
}
}
catch (error) {
status[name] = {
initialized: false,
error: error instanceof Error ? error.message : String(error),
};
}
});
return status;
}
/**
* Validate plugin system integrity
* @returns Object with validation results
*/
validatePluginSystem() {
const status = this.getPluginsInitializationStatus();
const totalPlugins = Object.keys(status).length;
const initializedPlugins = Object.values(status).filter((s) => s.initialized).length;
const failedPlugins = Object.entries(status)
.filter(([_, s]) => !s.initialized)
.map(([name, _]) => name);
const warnings = [];
if (totalPlugins === 0) {
warnings.push("No plugins registered");
}
if (failedPlugins.length > 0) {
warnings.push(`Failed plugins: ${failedPlugins.join(", ")}`);
}
return {
totalPlugins,
initializedPlugins,
failedPlugins,
warnings,
};
}
/**
* Attempt to reinitialize failed plugins
* @returns Object with reinitialization results
*/
reinitializeFailedPlugins() {
const status = this.getPluginsInitializationStatus();
const failedPlugins = Object.entries(status)
.filter(([_, s]) => !s.initialized)
.map(([name, _]) => name);
const success = [];
const failed = [];
failedPlugins.forEach((pluginName) => {
try {
const plugin = this.plugins.get(pluginName);
if (!plugin) {
failed.push({ name: pluginName, error: "Plugin not found" });
return;
}
// Reinizializza il plugin
if (pluginName === shogun_1.CorePlugins.OAuth) {
// Rimuovo la chiamata a initialize
plugin.initialize(this);
}
else {
// Rimuovo la chiamata a initialize
plugin.initialize(this);
}
success.push(pluginName);
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
failed.push({ name: pluginName, error: errorMessage });
if (typeof console !== "undefined" && console.error) {
console.error(`[ShogunCore] Failed to reinitialize plugin ${pluginName}:`, error);
}
}
});
return { success, failed };
}
/**
* Check plugin compatibility with current ShogunCore version
* @returns Object with compatibility information
*/
checkPluginCompatibility() {
const compatible = [];
const incompatible = [];
const unknown = [];
this.plugins.forEach((plugin) => {
const pluginInfo = {
name: plugin.name,
version: plugin.version || "unknown",
};
// Verifica se il plugin ha informazioni di compatibilità
if (typeof plugin.getCompatibilityInfo === "function") {
try {
const compatibilityInfo = plugin.getCompatibilityInfo();
if (compatibilityInfo && compatibilityInfo.compatible) {
compatible.push(pluginInfo);
}
else {
incompatible.push({
...pluginInfo,
reason: compatibilityInfo?.reason || "Unknown compatibility issue",
});
}
}
catch (error) {
unknown.push(pluginInfo);
}
}
else {
// Se non ha informazioni di compatibilità, considera sconosciuto
unknown.push(pluginInfo);
}
});
return { compatible, incompatible, unknown };
}
/**
* Get comprehensive debug information about the plugin system
* @returns Complete plugin system debug information
*/
getPluginSystemDebugInfo() {
const pluginsInfo = this.getPluginsInfo();
const initializationStatus = this.getPluginsInitializationStatus();
const plugins = pluginsInfo.map((info) => ({
...info,
initialized: initializationStatus[info.name]?.initialized || false,
error: initializationStatus[info.name]?.error,
}));
return {
shogunCoreVersion: ShogunCore.API_VERSION,
totalPlugins: this.getPluginCount(),
plugins,
initializationStatus,
validation: this.validatePluginSystem(),
compatibility: this.checkPluginCompatibility(),
};
}
/**
* Check if a plugin is registered
* @param name Name of the plugin to check
* @returns true if the plugin is registered, false otherwise
*/
hasPlugin(name) {
return this.plugins.has(name);
}
/**
* Get all plugins of a specific category
* @param category Category of plugins to filter
* @returns Array of plugins in the specified category
*/
getPluginsByCategory(category) {
const result = [];
this.plugins.forEach((plugin) => {
if (plugin._category === category) {
result.push(plugin);
}
});
return result;
}
/**
* Get an authentication method plugin by type
* @param type The type of authentication method
* @returns The authentication plugin or undefined if not available
* This is a more modern approach to accessing authentication methods
*/
getAuthenticationMethod(type) {
switch (type) {
case "webauthn":
return this.getPlugin(shogun_1.CorePlugins.WebAuthn);
case "web3":
return this.getPlugin(shogun_1.CorePlugins.Web3);
case "nostr":
return this.getPlugin(shogun_1.CorePlugins.Nostr);
case "oauth":
return this.getPlugin(shogun_1.CorePlugins.OAuth);
case "password":
default:
return {
login: async (username, password) => {
return await this.login(username, password);
},
signUp: async (username, password, confirm) => {
return await this.signUp(username, password, confirm);
},
};
}
}
// *********************************************************************************************************
// 🔐 ERROR HANDLER 🔐
// *********************************************************************************************************
/**
* Retrieve recent errors logged by the system
* @param count - Number of errors to retrieve (default: 10)
* @returns List of most recent errors
*/
getRecentErrors(count = 10) {
return errorHandler_1.ErrorHandler.getRecentErrors(count);
}
// *********************************************************************************************************
// 🔐 AUTHENTICATION
// *********************************************************************************************************
/**
* Check if user is logged in
* @returns {boolean} True if user is logged in, false otherwise
* @description Verifies authentication status by checking GunInstance login state
* and presence of authentication credentials in storage
*/
isLoggedIn() {
return this.db.isLoggedIn();
}
/**
* Perform user logout
* @description Logs out the current user from GunInstance and emits logout event.
* If user is not authenticated, the logout operation is ignored.
*/
logout() {
try {
if (!this.isLoggedIn()) {
return;
}
this.db.logout();
this.eventEmitter.emit("auth:logout");
}
catch (error) {
errorHandler_1.ErrorHandler.handle(errorHandler_1.ErrorType.AUTHENTICATION, "LOGOUT_FAILED", error instanceof Error ? error.message : "Error during logout", error);
}
}
/**
* Authenticate user with username and password
* @param username - Username
* @param password - User password
* @returns {Promise<AuthResult>} Promise with authentication result
* @description Attempts to log in user with provided credentials.
* Emits login event on success.
*/
async login(username, password, pair) {
try {
if (!this.currentAuthMethod) {
this.currentAuthMethod = "password";
}
const result = await this.db.login(username, password, pair);
if (result.success) {
// Include SEA pair in the response
const seaPair = this.user?._?.sea;
if (seaPair) {
result.sea = seaPair;
}
this.eventEmitter.emit("auth:login", {
userPub: result.userPub ?? "",
method: this.currentAuthMethod === "pair"
? "password"
: this.currentAuthMethod || "password",
});
}
else {
result.error = result.error || "Wrong user or password";
}
return result;
}
catch (error) {
errorHandler_1.ErrorHandler.handle(errorHandler_1.ErrorType.AUTHENTICATION, "LOGIN_FAILED", error.message ?? "Unknown error during login", error);
return {
success: false,
error: error.message ?? "Unknown error during login",
};
}
}
/**
* Login with GunDB pair directly
* @param pair - GunDB SEA pair for authentication
* @returns {Promise<AuthResult>} Promise with authentication result
* @description Authenticates user using a GunDB pair directly.
* Emits login event on success.
*/
async loginWithPair(pair) {
try {
if (!pair || !pair.pub || !pair.priv || !pair.epub || !pair.epriv) {
return {
success: false,
error: "Invalid pair structure - missing required keys",
};
}
// Use the new loginWithPair method from GunInstance
const result = await this.db.login("", "", pair);
if (result.success) {
// Include SEA pair in the response
const seaPair = this.user?._?.sea;
if (seaPair) {
result.sea = seaPair;
}
this.currentAuthMethod = "pair";
this.eventEmitter.emit("auth:login", {
userPub: result.userPub ?? "",
method: "password",
});
}
else {
result.error =
result.error || "Authentication failed with provided pair";
}
return result;
}
catch (error) {
errorHandler_1.ErrorHandler.handle(errorHandler_1.ErrorType.AUTHENTICATION, "PAIR_LOGIN_FAILED", error.message ?? "Unknown error during pair login", error);
return {
success: false,
error: error.message ?? "Unknown error during pair login",
};
}
}
/**
* Register a new user with provided credentials
* @param username - Username
* @param password - Password
* @param passwordConfirmation - Password confirmation
* @param pair - Pair of keys
* @returns {Promise<SignUpResult>} Registration result
* @description Creates a new user account with the provided credentials.
* Validates password requirements and emits signup event on success.
*/
async signUp(username, password = "", email = "", pair) {
try {
if (!this.db) {
throw new Error("Database not initialized");
}
const result = await this.db.signUp(username, password, pair);
if (result.success) {
// Update current authentication method
this.currentAuthMethod = pair ? "web3" : "password";
this.eventEmitter.emit("auth:signup", {
userPub: result.userPub,
username,
method: this.currentAuthMethod,
});
this.eventEmitter.emit("debug", {
action: "signup_success",
userPub: result.userPub,
method: this.currentAuthMethod,
});
}
else {
this.eventEmitter.emit("debug", {
action: "signup_failed",
error: result.error,
username,
});
}
return result;
}
catch (error) {
if (typeof console !== "undefined" && console.error) {
console.error(`Error during registration for user ${username}:`, error);
}
this.eventEmitter.emit("debug", {
action: "signup_error",
error: error instanceof Error ? error.message : String(error),
username,
});
return {
success: false,
error: `Registration failed: ${error instanceof Error ? error.message : String(error)}`,
};
}
}
// 📢 EVENT EMITTER 📢
/**
* Emits an event through the core's event emitter.
* Plugins should use this method to emit events instead of accessing the private eventEmitter directly.
* @param eventName The name of the event to emit.
* @param data The data to pass with the event.
* @returns {boolean} Indicates if the event had listeners.
*/
emit(eventName, data) {
return this.eventEmitter.emit(eventName, data);
}
/**
* Add an event listener
* @param eventName The name of the event to listen for
* @param listener The callback function to execute when the event is emitted
* @returns {this} Returns this instance for method chaining
*/
on(eventName, listener) {
this.eventEmitter.on(eventName, listener);
return this;
}
/**
* Add a one-time event listener
* @param eventName The name of the event to listen for
* @param listener The callback function to execute when the event is emitted
* @returns {this} Returns this instance for method chaining
*/
once(eventName, listener) {
this.eventEmitter.once(eventName, listener);
return this;
}
/**
* Remove an event listener
* @param eventName The name of the event to stop listening for
* @param listener The callback function to remove
* @returns {this} Returns this instance for method chaining
*/
off(eventName, listener) {
this.eventEmitter.off(eventName, listener);
return this;
}
/**
* Remove all listeners for a specific event or all events
* @param eventName Optional. The name of the event to remove listeners for.
* If not provided, all listeners for all events are removed.
* @returns {this} Returns this instance for method chaining
*/
removeAllListeners(eventName) {
this.eventEmitter.removeAllListeners(eventName);
return this;
}
/**
* Set the current authentication method
* This is used by plugins to indicate which authentication method was used
* @param method The authentication method used
*/
setAuthMethod(method) {
this.currentAuthMethod = method;
}
/**
* Get the current authentication method
* @returns The current authentication method or undefined if not set
*/
getAuthMethod() {
return this.currentAuthMethod;
}
/**
* Clears all Gun-related data from local and session storage
* This is useful for debugging and testing purposes
*/
clearAllStorageData() {
this.db.clearGunStorage();
}
/**
* Updates the user's alias (username) in Gun and saves the updated credentials
* @param newAlias New alias/username to set
* @returns Promise resolving to update result
*/
async updateUserAlias(newAlias) {
try {
if (!this.db) {
return false;
}
const result = await this.db.updateUserAlias(newAlias);
return result.success;
}
catch (error) {
if (typeof console !== "undefined" && console.error) {
console.error(`Error updating user alias:`, error);
}
return false;
}
}
/**
* Saves the current user credentials to storage
*/
async saveCredentials(credentials) {
try {
this.storage.setItem("userCredentials", JSON.stringify(credentials));
}
catch (error) {
if (typeof console !== "undefined" && console.warn) {
console.warn("Failed to save credentials to storage");
}
if (typeof console !== "undefined" && console.error) {
console.error(`Error saving credentials:`, error);
}
}
}
// esporta la coppia utente come json
/**
* Esporta la coppia di chiavi dell'utente corrente come stringa JSON.
* Utile per backup o migrazione dell'account.
* @returns {string} La coppia SEA serializzata in formato JSON, oppure stringa vuota se non disponibile.
*/
exportPair() {
if (!this.user ||
!this.user._ ||
typeof this.user._.sea === "undefined") {
return "";
}
return JSON.stringify(this.user._.sea);
}
getIsLoggedIn() {
return !!(this.user && this.user.is);
}
/**
* Changes the username for the currently authenticated user
* @param newUsername New username to set
* @returns Promise resolving to the operation result
*/
async changeUsername(newUsername) {
try {
if (!this.db) {
throw new Error("Database not initialized");
}
const result = await this.db.changeUsername(newUsername);
if (result.success) {
this.eventEmitter.emit("auth:username_changed", {
oldUsername: result.oldUsername,
newUsername: result.newUsername,
userPub: this.getCurrentUser()?.pub,
});
this.eventEmitter.emit("debug", {
action: "username_changed",
oldUsername: result.oldUsername,
newUsername: result.newUsername,
});
}
else {
this.eventEmitter.emit("debug", {
action: "username_change_failed",
error: result.error,
newUsername,
});
}
return result;
}
catch (error) {
if (typeof console !== "undefined" && console.error) {
console.error(`Error changing username to ${newUsername}:`, error);
}
this.eventEmitter.emit("debug", {
action: "username_change_error",
error: error instanceof Error ? error.message : String(error),
newUsername,
});
return {
success: false,
error: `Username change failed: ${error instanceof Error ? error.message : String(error)}`,
};
}
}
}
exports.ShogunCore = ShogunCore;
exports.default = ShogunCore;
if (typeof window !== "undefined") {
window.ShogunCoreClass = ShogunCore;
}
if (typeof window !== "undefined") {
window.initShogun = (config) => {
const instance = new ShogunCore(config);
window.ShogunCore = instance;
return instance;
};
}