UNPKG

shogun-core

Version:

SHOGUN CORE - Core library for Shogun Ecosystem

957 lines (956 loc) โ€ข 46.3 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; import { RxJS } from './rxjs.js'; import { EventEmitter } from '../utils/eventEmitter.js'; import * as GunErrors from './errors.js'; import * as crypto from './crypto.js'; /** * GunDB configuration constants. * @internal */ var CONFIG = { PASSWORD: { MIN_LENGTH: 8, }, }; /** * DataBase * * Manages GunDB user authentication and various utility helpers for * session, alias/username, SEA cryptography, event handling, and reactive streams. */ var DataBase = /** @class */ (function () { /** * Constructs a new DataBase instance connected to a GunDB instance. * @param gun The main GunDB instance. * @param core Optionally, the root Gun instance (unused in this context). * @param sea Optional cryptography (Gun SEA) instance; will be auto-discovered if not provided. * @throws If gun or gun.user() is not provided. */ function DataBase(gun, core, sea) { var _a; /** Cached user instance or `null` if not logged in */ this.user = null; /** Registered callbacks for auth state changes */ this.onAuthCallbacks = []; /** Whether the database instance has been destroyed */ this._isDestroyed = false; this.eventEmitter = new EventEmitter(); this.core = core; if (!gun) { throw new Error('Gun instance is required but was not provided'); } if (typeof gun.user !== 'function') { throw new Error('Gun instance is invalid: gun.user is not a function'); } this.gun = gun; this.user = this.gun.user().recall({ sessionStorage: true }); this.subscribeToAuthEvents(); this.crypto = crypto; this.sea = sea || null; if (!this.sea) { if (this.gun.SEA) { this.sea = this.gun.SEA; } else if ((_a = globalThis.Gun) === null || _a === void 0 ? void 0 : _a.SEA) { this.sea = globalThis.Gun.SEA; } else if (globalThis.SEA) { this.sea = globalThis.SEA; } } this._rxjs = new RxJS(this.gun); this.usernamesNode = this.gun.get('usernames'); console.log('[DB] DataBase initialization completed'); } /** * Initialize the database instance. */ DataBase.prototype.initialize = function () { // Database is already initialized in constructor }; /** * Internal: subscribe to GunDB "auth" events and notify listeners. * Listeners are invoked on authentication status change. * @internal */ DataBase.prototype.subscribeToAuthEvents = function () { var _this = this; this.gun.on('auth', function (ack) { var _a; if (ack.err) { console.error('[DB] Auth event error:', ack.err); } else { _this.notifyAuthListeners(((_a = ack.sea) === null || _a === void 0 ? void 0 : _a.pub) || ''); } }); }; /** * Internal: notify all onAuth callbacks with current user. * @param pub User's public key (pub). * @internal */ DataBase.prototype.notifyAuthListeners = function (pub) { var user = this.gun.user(); this.onAuthCallbacks.forEach(function (cb) { return cb(user); }); }; /** * Listen for authentication/sign-in events (login, logout, etc). * @param callback Function to call with new user instance. * @returns Function to remove the registered callback. */ DataBase.prototype.onAuth = function (callback) { var _this = this; this.onAuthCallbacks.push(callback); var user = this.gun.user(); if (user && user.is) callback(user); return function () { var i = _this.onAuthCallbacks.indexOf(callback); if (i !== -1) _this.onAuthCallbacks.splice(i, 1); }; }; /** * Check if a user is currently logged in (there is a valid session). * @returns `true` if logged in; otherwise `false`. */ DataBase.prototype.isLoggedIn = function () { try { var user = this.gun.user(); return !!(user && user.is && user.is.pub); } catch (error) { return false; } }; /** * Attempt to restore a previously saved session from sessionStorage. * @returns Object indicating success, error, and userPub if restored. */ DataBase.prototype.restoreSession = function () { try { if (typeof sessionStorage === 'undefined') { return { success: false, error: 'sessionStorage not available' }; } var sessionData = sessionStorage.getItem('gunSessionData'); if (!sessionData) { return { success: false, error: 'No saved session' }; } var session = JSON.parse(sessionData); if (!session.userPub) { return { success: false, error: 'Invalid session data' }; } // Check if session is expired if (session.expiresAt && Date.now() > session.expiresAt) { sessionStorage.removeItem('gunSessionData'); return { success: false, error: 'Session expired' }; } // Verify session restoration var user = this.gun.user(); if (user.is && user.is.pub === session.userPub) { this.user = user; return { success: true, userPub: session.userPub }; } return { success: false, error: 'Session verification failed' }; } catch (error) { return { success: false, error: String(error) }; } }; /** * Log out the current user, clear local state and remove session from storage. */ DataBase.prototype.logout = function () { try { var wasLoggedIn = !!this.user; var currentUser = this.gun.user(); if (currentUser && currentUser.is) { currentUser.leave(); } this.user = null; if (typeof sessionStorage !== 'undefined') { sessionStorage.removeItem('gunSessionData'); } // Emit auth:logout event if core is available and user was logged in if (wasLoggedIn && this.core && typeof this.core.emit === 'function') { this.core.emit('auth:logout', undefined); } } catch (error) { console.error('[DB] Error during logout:', error); } }; /** * Validate that a provided password meets minimum length requirements. * @param password Password string to validate. * @returns Object indicating validity and, if invalid, an error. */ DataBase.prototype.validatePasswordStrength = function (password) { if (password.length < CONFIG.PASSWORD.MIN_LENGTH) { return { valid: false, error: "Password must be at least ".concat(CONFIG.PASSWORD.MIN_LENGTH, " characters long"), }; } return { valid: true }; }; /** * Validate a signup request's username, password, and/or cryptographic pair. * @param username Username string. * @param password Password string. * @param pair Optional cryptographic SEA pair. * @returns Object with validation status and optional error. */ DataBase.prototype.validateSignupCredentials = function (username, password, pair) { if (!username || username.length < 1) { return { valid: false, error: 'Username must be more than 0 characters long', }; } if (!/^[a-zA-Z0-9._-]+$/.test(username)) { return { valid: false, error: 'Username can only contain letters, numbers, dots, underscores, and hyphens', }; } if (pair) { if (!pair.pub || !pair.priv || !pair.epub || !pair.epriv) { return { valid: false, error: 'Invalid pair provided' }; } return { valid: true }; } return this.validatePasswordStrength(password); }; /** * Ensures that an alias/username is available in GunDB for registration. * @param alias Username to check. * @param timeout Timeout in milliseconds (default 5000ms). * @throws If the alias is already taken. */ DataBase.prototype.ensureAliasAvailable = function (alias_1) { return __awaiter(this, arguments, void 0, function (alias, timeout) { var available; if (timeout === void 0) { timeout = 5000; } return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.isAliasAvailable(alias, timeout)]; case 1: available = _a.sent(); if (!available) { throw new Error("Alias \"".concat(alias, "\" is already registered in Gun")); } return [2 /*return*/]; } }); }); }; /** * Checks if a given alias/username is available on GunDB. * @param alias Username to check for availability. * @param timeout Timeout in ms (default: 5000). * @returns Promise resolving to `true` if available; otherwise `false`. * @throws If alias is invalid or on I/O error. */ DataBase.prototype.isAliasAvailable = function (alias_1) { return __awaiter(this, arguments, void 0, function (alias, timeout) { var normalizedAlias; var _this = this; if (timeout === void 0) { timeout = 5000; } return __generator(this, function (_a) { if (typeof alias !== 'string' || !alias.trim()) { throw new Error('Alias must be a non-empty string'); } normalizedAlias = alias.trim().toLowerCase(); return [2 /*return*/, new Promise(function (resolve, reject) { var settled = false; var timer = setTimeout(function () { if (settled) return; settled = true; reject(new Error('Timeout while checking alias availability')); }, timeout); _this.usernamesNode.get(normalizedAlias).once(function (existingPub) { if (settled) return; settled = true; clearTimeout(timer); resolve(!existingPub); }); })]; }); }); }; /** * Checks if a given alias/username is taken on GunDB. * @param alias Username to check for availability. * @returns Promise resolving to `true` if taken; otherwise `false`. * @throws If alias is invalid or on I/O error. */ DataBase.prototype.isAliasTaken = function (alias) { return __awaiter(this, void 0, void 0, function () { var _this = this; return __generator(this, function (_a) { return [2 /*return*/, new Promise(function (resolve, reject) { // Check if username exists by looking up ~@username _this.gun.get("~@".concat(alias)).once(function (user) { // If user exists, alias is taken (return true) // If user is null/undefined, alias is available (return false) resolve(!!user); }); })]; }); }); }; /** * Register a new alias (username) โ†’ public key mapping on GunDB. * @param alias The username/alias to register. * @param userPub The user's public key. * @param timeout Timeout in ms (default 5000). * @throws If alias/userPub is invalid or the alias cannot be registered. */ DataBase.prototype.registerAlias = function (alias_1, userPub_1) { return __awaiter(this, arguments, void 0, function (alias, userPub, timeout) { var normalizedAlias, available, taken; var _this = this; if (timeout === void 0) { timeout = 5000; } return __generator(this, function (_a) { switch (_a.label) { case 0: if (!alias || !alias.trim()) { throw new Error('Alias must be provided for registration'); } if (!userPub) { throw new Error('userPub must be provided for alias registration'); } normalizedAlias = alias.trim().toLowerCase(); return [4 /*yield*/, this.isAliasAvailable(normalizedAlias, timeout).catch(function (error) { console.error('[DB] Alias availability check failed:', error); throw error; })]; case 1: available = _a.sent(); return [4 /*yield*/, this.isAliasTaken(normalizedAlias)]; case 2: taken = _a.sent(); if (taken) { throw new Error("Alias \"".concat(normalizedAlias, "\" is already taken")); } if (!available) { throw new Error("Alias \"".concat(normalizedAlias, "\" is no longer available for registration")); } return [4 /*yield*/, new Promise(function (resolve, reject) { var settled = false; var timer = setTimeout(function () { if (settled) return; settled = true; reject(new Error('Timeout while registering alias')); }, timeout); _this.usernamesNode.get(normalizedAlias).put(userPub, function (ack) { if (settled) return; settled = true; clearTimeout(timer); if (ack && ack.err) { reject(new Error(String(ack.err))); return; } resolve(); }); }).catch(function (error) { console.error('[DB] Failed to register alias:', error); throw error; })]; case 3: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Reset gun.user() authentication state and clear cached user. * @internal */ DataBase.prototype.resetAuthState = function () { try { var user = this.gun.user(); if (user && user._) { var cat = user._; cat.ing = false; cat.auth = null; cat.act = null; if (cat.auth) { cat.auth = null; } } try { user.leave(); } catch (leaveError) { // Ignore leave errors } this.user = null; } catch (e) { // Ignore } }; /** * Assemble a standard AuthResult object after a successful login. * @param username Resulting username. * @param userPub Public key (pub) for logged-in user. * @returns AuthResult. * @internal */ DataBase.prototype.buildLoginResult = function (username, userPub) { var _a, _b; var seaPair = (_b = (_a = this.gun.user()) === null || _a === void 0 ? void 0 : _a._) === null || _b === void 0 ? void 0 : _b.sea; return { success: true, userPub: userPub, username: username, sea: seaPair ? { pub: seaPair.pub, priv: seaPair.priv, epub: seaPair.epub, epriv: seaPair.epriv, } : undefined, }; }; /** * Save credentials for the current session to sessionStorage, if available. * @param userInfo The credentials and user identity to store. */ DataBase.prototype.saveCredentials = function (userInfo) { try { if (typeof sessionStorage !== 'undefined') { var sessionInfo = { username: userInfo.alias, pair: userInfo.pair, userPub: userInfo.userPub, timestamp: Date.now(), expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 days }; sessionStorage.setItem('gunSessionData', JSON.stringify(sessionInfo)); } } catch (error) { console.error('[DB] Error saving credentials:', error); } }; /** * Register and authenticate a new user account. * @param username The username to create/account for. * @param password The user's password. * @param pair Optional cryptographic pair (for `auth` instead of password). * @returns SignUpResult Promise. */ DataBase.prototype.signUp = function (username, password, pair) { return __awaiter(this, void 0, void 0, function () { var validation, normalizedUsername, user, loginResult, e_1, aliasError_1, result; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: validation = this.validateSignupCredentials(username, password, pair); if (!validation.valid) { return [2 /*return*/, { success: false, error: validation.error }]; } this.resetAuthState(); normalizedUsername = username.trim().toLowerCase(); user = this.gun.user(); if (!pair) return [3 /*break*/, 4]; _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, new Promise(function (resolve) { var callbackInvoked = false; user.auth(pair, function (ack) { var _a, _b, _c; if (callbackInvoked) { return; } callbackInvoked = true; if (ack.err) { resolve({ success: false, error: ack.err }); return; } var userPub = (_a = user === null || user === void 0 ? void 0 : user.is) === null || _a === void 0 ? void 0 : _a.pub; if (!userPub) { _this.resetAuthState(); resolve({ success: false, error: 'No userPub available' }); return; } _this.user = user; var alias = (_b = user === null || user === void 0 ? void 0 : user.is) === null || _b === void 0 ? void 0 : _b.alias; var userPair = (_c = user === null || user === void 0 ? void 0 : user._) === null || _c === void 0 ? void 0 : _c.sea; _this.saveCredentials({ alias: alias || normalizedUsername, pair: pair !== null && pair !== void 0 ? pair : userPair, userPub: userPub, }); // Emit auth:signup event if core is available (pair-based signup) if (_this.core && typeof _this.core.emit === 'function') { _this.core.emit('auth:signup', { userPub: userPub, username: normalizedUsername, method: 'pair', }); } resolve(_this.buildLoginResult(alias || normalizedUsername, userPub)); }); })]; case 2: loginResult = _a.sent(); if (loginResult && loginResult.success) { return [2 /*return*/, loginResult]; } return [3 /*break*/, 4]; case 3: e_1 = _a.sent(); return [3 /*break*/, 4]; case 4: _a.trys.push([4, 6, , 7]); return [4 /*yield*/, this.ensureAliasAvailable(normalizedUsername)]; case 5: _a.sent(); return [3 /*break*/, 7]; case 6: aliasError_1 = _a.sent(); return [2 /*return*/, { success: false, error: aliasError_1 instanceof Error ? aliasError_1.message : String(aliasError_1), }]; case 7: return [4 /*yield*/, new Promise(function (resolve) { var callbackInvoked = false; user.create(normalizedUsername, password, function (createAck) { if (callbackInvoked) { return; } if (createAck.err || (createAck.ok !== undefined && createAck.ok !== 0)) { callbackInvoked = true; _this.resetAuthState(); resolve({ success: false, error: createAck.err || 'Signup failed' }); return; } var userPub = createAck.pub; if (!userPub) { callbackInvoked = true; _this.resetAuthState(); resolve({ success: false, error: 'No userPub available from signup', }); return; } user.auth(normalizedUsername, password, function (authAck) { return __awaiter(_this, void 0, void 0, function () { var authenticatedUserPub, alias, userPair, registerError_1, sea; var _a, _b, _c, _d; return __generator(this, function (_e) { switch (_e.label) { case 0: if (callbackInvoked) { return [2 /*return*/]; } callbackInvoked = true; if (authAck.err) { this.resetAuthState(); resolve({ success: false, error: authAck.err || 'Authentication after signup failed', }); return [2 /*return*/]; } authenticatedUserPub = (_a = user === null || user === void 0 ? void 0 : user.is) === null || _a === void 0 ? void 0 : _a.pub; if (!authenticatedUserPub) { this.resetAuthState(); resolve({ success: false, error: 'User not authenticated after signup', }); return [2 /*return*/]; } this.user = user; alias = (_b = user === null || user === void 0 ? void 0 : user.is) === null || _b === void 0 ? void 0 : _b.alias; userPair = (_c = user === null || user === void 0 ? void 0 : user._) === null || _c === void 0 ? void 0 : _c.sea; try { this.saveCredentials({ alias: alias || normalizedUsername, pair: pair !== null && pair !== void 0 ? pair : userPair, userPub: authenticatedUserPub, }); } catch (saveError) { // Ignore save errors } _e.label = 1; case 1: _e.trys.push([1, 3, , 4]); return [4 /*yield*/, this.registerAlias(alias || normalizedUsername, authenticatedUserPub)]; case 2: _e.sent(); return [3 /*break*/, 4]; case 3: registerError_1 = _e.sent(); console.error('[DB] Alias registration failed:', registerError_1); return [3 /*break*/, 4]; case 4: // Emit auth:signup event if core is available if (this.core && typeof this.core.emit === 'function') { this.core.emit('auth:signup', { userPub: authenticatedUserPub, username: normalizedUsername, method: pair ? 'pair' : 'password', }); } sea = (_d = user === null || user === void 0 ? void 0 : user._) === null || _d === void 0 ? void 0 : _d.sea; resolve({ success: true, userPub: authenticatedUserPub, username: normalizedUsername, isNewUser: true, sea: sea ? { pub: sea.pub, priv: sea.priv, epub: sea.epub, epriv: sea.epriv, } : undefined, }); return [2 /*return*/]; } }); }); }); }); })]; case 8: result = _a.sent(); return [2 /*return*/, result]; } }); }); }; /** * Sign in (authenticate) as an existing user by username/password or SEA pair. * @param username Username to log in as. * @param password User's password (or "" if using pair). * @param pair Optional cryptographic SEA pair. * @returns AuthResult Promise. */ DataBase.prototype.login = function (username, password, pair) { return __awaiter(this, void 0, void 0, function () { var normalizedUsername, user; var _this = this; return __generator(this, function (_a) { this.resetAuthState(); normalizedUsername = username.trim().toLowerCase(); user = this.gun.user(); return [2 /*return*/, new Promise(function (resolve) { if (pair) { user.auth(pair, function (ack) { var _a, _b, _c; if (ack.err) { _this.resetAuthState(); resolve({ success: false, error: ack.err }); return; } var userPub = (_a = user === null || user === void 0 ? void 0 : user.is) === null || _a === void 0 ? void 0 : _a.pub; if (!userPub) { _this.resetAuthState(); resolve({ success: false, error: 'No userPub available' }); return; } _this.user = user; var alias = (_b = user === null || user === void 0 ? void 0 : user.is) === null || _b === void 0 ? void 0 : _b.alias; var userPair = (_c = user === null || user === void 0 ? void 0 : user._) === null || _c === void 0 ? void 0 : _c.sea; try { _this.saveCredentials({ alias: alias || normalizedUsername, pair: pair !== null && pair !== void 0 ? pair : userPair, userPub: userPub, }); } catch (saveError) { // Ignore save errors } // Emit auth:login event if core is available (pair-based login) if (_this.core && typeof _this.core.emit === 'function') { _this.core.emit('auth:login', { userPub: userPub, username: alias || normalizedUsername, method: 'pair', }); } resolve(_this.buildLoginResult(alias || normalizedUsername, userPub)); }); } else { user.auth(normalizedUsername, password, function (ack) { var _a, _b, _c; if (ack.err) { _this.resetAuthState(); resolve({ success: false, error: ack.err }); return; } var userPub = (_a = user === null || user === void 0 ? void 0 : user.is) === null || _a === void 0 ? void 0 : _a.pub; if (!userPub) { _this.resetAuthState(); resolve({ success: false, error: 'No userPub available' }); return; } _this.user = user; var alias = (_b = user === null || user === void 0 ? void 0 : user.is) === null || _b === void 0 ? void 0 : _b.alias; var userPair = (_c = user === null || user === void 0 ? void 0 : user._) === null || _c === void 0 ? void 0 : _c.sea; try { _this.saveCredentials({ alias: alias || normalizedUsername, pair: pair !== null && pair !== void 0 ? pair : userPair, userPub: userPub, }); } catch (saveError) { // Ignore save errors } // Emit auth:login event if core is available (password-based login) if (_this.core && typeof _this.core.emit === 'function') { _this.core.emit('auth:login', { userPub: userPub, username: alias || normalizedUsername, method: 'password', }); } resolve(_this.buildLoginResult(alias || normalizedUsername, userPub)); }); } })]; }); }); }; /** * Returns the currently authenticated user's public key and Gun user instance, if logged in. * @returns Object containing `pub` (public key) and optionally `user`, or `null`. */ DataBase.prototype.getCurrentUser = function () { try { var user = this.gun.user(); if (user && user.is && user.is.pub) { return { pub: user.is.pub, user: user, }; } return null; } catch (error) { return null; } }; /** * Get current user's public key. * @returns User's public key or null if not logged in. */ DataBase.prototype.getUserPub = function () { var _a; try { var user = this.gun.user(); return ((_a = user === null || user === void 0 ? void 0 : user.is) === null || _a === void 0 ? void 0 : _a.pub) || null; } catch (error) { return null; } }; /** * Authenticate using a SEA pair directly (no password required). * @param username The user's username for identification (not cryptographically enforced). * @param pair GunDB SEA pair for authentication. * @returns Promise with authentication result. * @description Authenticates user using a GunDB pair directly without password. */ DataBase.prototype.loginWithPair = function (username, pair) { return __awaiter(this, void 0, void 0, function () { var normalizedUsername, user; var _this = this; return __generator(this, function (_a) { // Validate pair structure if (!pair || !pair.pub || !pair.priv || !pair.epub || !pair.epriv) { return [2 /*return*/, { success: false, error: 'Invalid pair structure - missing required keys', }]; } this.resetAuthState(); normalizedUsername = username.trim().toLowerCase(); user = this.gun.user(); console.log('[DB] Login with pair for username:', normalizedUsername); return [2 /*return*/, new Promise(function (resolve) { user.auth(pair, function (ack) { var _a, _b, _c; if (ack.err) { _this.resetAuthState(); resolve({ success: false, error: ack.err }); return; } var userPub = (_a = user === null || user === void 0 ? void 0 : user.is) === null || _a === void 0 ? void 0 : _a.pub; if (!userPub) { _this.resetAuthState(); resolve({ success: false, error: 'No userPub available' }); return; } _this.user = user; var alias = (_b = user === null || user === void 0 ? void 0 : user.is) === null || _b === void 0 ? void 0 : _b.alias; var userPair = (_c = user === null || user === void 0 ? void 0 : user._) === null || _c === void 0 ? void 0 : _c.sea; try { _this.saveCredentials({ alias: alias || normalizedUsername, pair: pair !== null && pair !== void 0 ? pair : userPair, userPub: userPub, }); } catch (saveError) { // Ignore save errors } // Emit auth:login event if core is available (loginWithPair) if (_this.core && typeof _this.core.emit === 'function') { _this.core.emit('auth:login', { userPub: userPub, username: alias || normalizedUsername, method: 'pair', }); } resolve(_this.buildLoginResult(alias || normalizedUsername, userPub)); }); })]; }); }); }; /** * Legacy API: Sign in using a username and SEA pair (password parameter is unused). * @param username Username to sign in as. * @param pair SEA key pair. * @returns AuthResult Promise. */ DataBase.prototype.loginWithPairLegacy = function (username, pair) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.login(username, '', pair)]; }); }); }; /** * Returns the bound RxJS GunDB helper (reactive streams). * @returns RxJS instance. */ DataBase.prototype.rx = function () { return this._rxjs; }; /** * Tears down the DataBase instance and performs cleanup of all resources/listeners. * No further actions should be performed on this instance after destruction. */ DataBase.prototype.destroy = function () { if (this._isDestroyed) return; console.log('[DB] Destroying DataBase instance...'); this._isDestroyed = true; this.onAuthCallbacks.length = 0; this.eventEmitter.removeAllListeners(); if (this.user) { try { this.user.leave(); } catch (error) { // Ignore } this.user = null; } this._rxjs = undefined; console.log('[DB] DataBase instance destroyed'); }; /** * Aggressively clean up authentication state and session. Typically used for error recovery. */ DataBase.prototype.aggressiveAuthCleanup = function () { console.log('๐Ÿงน Performing aggressive auth cleanup...'); this.resetAuthState(); this.logout(); console.log('โœ“ Aggressive auth cleanup completed'); }; /** * Register an event handler. * @param event Event name. * @param listener Listener function. */ DataBase.prototype.on = function (event, listener) { this.eventEmitter.on(event, listener); }; /** * Remove an event handler. * @param event Event name. * @param listener Listener function. */ DataBase.prototype.off = function (event, listener) { this.eventEmitter.off(event, listener); }; /** * Register an event handler for a single event occurrence. * @param event Event name. * @param listener Listener function. */ DataBase.prototype.once = function (event, listener) { this.eventEmitter.once(event, listener); }; /** * Emit a custom event. * @param event Event name. * @param data Optional associated data. * @returns `true` if listeners were notified; otherwise `false`. */ DataBase.prototype.emit = function (event, data) { return this.eventEmitter.emit(event, data); }; return DataBase; }()); export { DataBase, RxJS, crypto, GunErrors }; export { default as derive } from './derive.js';