rashi-discord-bot-lib
Version:
🚀 Powerful Discord bot framework with built-in database, event handling, and utilities
249 lines • 9.1 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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.VerseDB = void 0;
// src/database/VerseDB.ts
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const JsonAdapter_1 = require("./adapters/JsonAdapter");
const YamlAdapter_1 = require("./adapters/YamlAdapter");
const MongoAdapter_1 = require("./adapters/MongoAdapter");
const SQLAdapter_1 = require("./adapters/SQLAdapter");
const Crypto_1 = require("../utils/Crypto");
const Logger_1 = require("../utils/Logger");
class VerseDB {
adapter;
config;
logger;
data = {};
isInitialized = false;
constructor(config, logger) {
this.config = config;
this.logger = logger || new Logger_1.Logger();
this.adapter = this.createAdapter();
}
/** Initialize the database */
async initialize() {
try {
if (typeof this.adapter.connect === 'function') {
await this.adapter.connect();
}
if (this.isFileBased() && this.config.path) {
if (!fs.existsSync(this.config.path)) {
fs.mkdirSync(this.config.path, { recursive: true });
}
}
let exists = false;
try {
exists = this.adapter.exists();
}
catch {
exists = false;
}
if (exists) {
const raw = await this.adapter.read();
this.data = this.config.secure?.enable && this.config.secure.secret
? this.decryptData(raw)
: (raw ?? {});
}
else {
this.data = {};
await this.save();
}
this.isInitialized = true;
}
catch (error) {
this.logger.error('Failed to initialize VerseDB:', error);
throw error;
}
}
get(key) {
this.checkInitialized();
const keys = key.split('.');
let current = this.data;
for (const k of keys) {
if (current && typeof current === 'object' && k in current)
current = current[k];
else
return undefined;
}
return current;
}
async set(key, value) {
this.checkInitialized();
const keys = key.split('.');
let current = this.data;
for (let i = 0; i < keys.length - 1; i++) {
const k = keys[i];
if (!current[k] || typeof current[k] !== 'object')
current[k] = {};
current = current[k];
}
current[keys[keys.length - 1]] = value;
await this.save();
}
async delete(key) {
this.checkInitialized();
const keys = key.split('.');
let current = this.data;
for (let i = 0; i < keys.length - 1; i++) {
const k = keys[i];
if (!current[k] || typeof current[k] !== 'object')
return;
current = current[k];
}
delete current[keys[keys.length - 1]];
await this.save();
}
has(key) {
return this.get(key) !== undefined;
}
all() {
this.checkInitialized();
return Object.entries(this.data).map(([key, value]) => ({ key, value }));
}
async clear() {
this.checkInitialized();
this.data = {};
await this.save();
}
async backup(backupPath) {
this.checkInitialized();
const baseDir = this.config.path ?? process.cwd();
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupFile = backupPath || path.join(baseDir, `backup-${timestamp}.json`);
await this.adapter.backup(backupFile);
this.logger.info(`📦 Database backed up to: ${backupFile}`);
}
async restore(backupPath) {
this.checkInitialized();
await this.adapter.restore(backupPath);
const raw = await this.adapter.read();
this.data = this.config.secure?.enable && this.config.secure.secret
? this.decryptData(raw)
: (raw ?? {});
this.logger.info(`📥 Database restored from: ${backupPath}`);
}
async getStats() {
this.checkInitialized();
const dataString = JSON.stringify(this.data);
return {
size: Buffer.byteLength(dataString, 'utf8'),
keys: Object.keys(this.data).length,
adapter: this.config.adapterType
};
}
async healthCheck() {
try {
return this.isInitialized && this.adapter.exists();
}
catch {
return false;
}
}
async close() {
if (!this.isInitialized)
return;
await this.save();
if (typeof this.adapter.disconnect === 'function') {
await this.adapter.disconnect();
}
this.isInitialized = false;
this.logger.info('🗃️ VerseDB connection closed');
}
async save() {
let toSave = this.data;
if (this.config.secure?.enable && this.config.secure.secret) {
toSave = this.encryptData(this.data);
}
await this.adapter.write(toSave);
}
createAdapter() {
switch (this.config.adapterType) {
case 'json': {
if (!this.config.path)
throw new Error('VerseConfig.path is required for JSON adapter');
const filePath = path.join(this.config.path, `database.json`);
return new JsonAdapter_1.JsonAdapter(filePath);
}
case 'yaml': {
if (!this.config.path)
throw new Error('VerseConfig.path is required for YAML adapter');
const filePath = path.join(this.config.path, `database.yaml`);
return new YamlAdapter_1.YamlAdapter(filePath);
}
case 'mongo': {
const uri = this.config.mongoURI;
if (!uri)
throw new Error('VerseConfig.mongoURI is required for Mongo adapter');
const dbName = this.config.dbName ?? 'verse';
const collection = this.config.collection ?? 'versedb';
const documentId = this.config.documentId ?? 'versedb_data';
return new MongoAdapter_1.MongoAdapter(uri, dbName, collection, documentId);
}
case 'sqlite': {
if (!this.config.path)
throw new Error('VerseConfig.path is required for SQLite adapter');
const filePath = path.join(this.config.path, `database.sqlite`);
return new SQLAdapter_1.SQLAdapter(filePath);
}
default:
throw new Error(`Unsupported adapter type: ${this.config.adapterType}`);
}
}
isFileBased() {
return ['json', 'yaml', 'sqlite'].includes(this.config.adapterType);
}
encryptData(data) {
if (!this.config.secure?.secret)
return data;
const dataString = JSON.stringify(data);
const encrypted = Crypto_1.Crypto.encrypt(dataString, this.config.secure.secret);
return { __encrypted: encrypted };
}
decryptData(data) {
if (!this.config.secure?.secret || !data?.__encrypted)
return data;
const decrypted = Crypto_1.Crypto.decrypt(data.__encrypted, this.config.secure.secret);
return JSON.parse(decrypted);
}
checkInitialized() {
if (!this.isInitialized) {
throw new Error('VerseDB not initialized. Call initialize() first.');
}
}
}
exports.VerseDB = VerseDB;
//# sourceMappingURL=VerseDB.js.map