yq-store
Version:
A high-performance, persistent and in-memory key-value store with TTL support, built for Node.js applications.
251 lines (241 loc) • 45.7 kB
JavaScript
"use strict";var Z=Object.create;var R=Object.defineProperty;var ee=Object.getOwnPropertyDescriptor;var te=Object.getOwnPropertyNames;var se=Object.getPrototypeOf,ie=Object.prototype.hasOwnProperty;var W=(a,e)=>()=>(a&&(e=a(a=0)),e);var H=(a,e)=>{for(var t in e)R(a,t,{get:e[t],enumerable:!0})},K=(a,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of te(e))!ie.call(a,i)&&i!==t&&R(a,i,{get:()=>e[i],enumerable:!(s=ee(e,i))||s.enumerable});return a};var E=(a,e,t)=>(t=a!=null?Z(se(a)):{},K(e||!a||!a.__esModule?R(t,"default",{value:a,enumerable:!0}):t,a)),ne=a=>K(R({},"__esModule",{value:!0}),a);var b,p,u,O,v=W(()=>{"use strict";b="_default",p=9007199254740991,u=1,O=["namespace","key","value","created_at","expires_at","is_deleted","last_accessed"]});var U={};H(U,{checkSchema:()=>L,findDatabases:()=>F,migrate:()=>z});function w(){return typeof Bun<"u"&&!!Bun?.version}async function Q(a){if(w()){let{Database:e}=await import("bun:sqlite");return new e(a)}else{let{DatabaseSync:e}=await import("node:sqlite");return new e(a)}}function A(a,e){a.exec(e)}function P(a,e){return w()?a.query(e).get():a.prepare(e).get()}function ae(a,e){return w()?a.query(e).all():a.prepare(e).all()}function Y(a){a.close()}async function L(a){if(!N.default.existsSync(a))return{needsMigration:!1,validation:{isValid:!0,expectedVersion:1,missingColumns:[],extraColumns:[]},dbPath:a,exists:!1};let t=await Q(a);try{if(!P(t,"SELECT name FROM sqlite_master WHERE type='table' AND name='kv_store'"))return{needsMigration:!1,validation:{isValid:!0,expectedVersion:1,missingColumns:[],extraColumns:[]},dbPath:a,exists:!0};let r=ae(t,"PRAGMA table_info(kv_store)").map(m=>m.name),n;try{if(P(t,"SELECT name FROM sqlite_master WHERE type='table' AND name='yq_meta'")){let _=P(t,"SELECT value FROM yq_meta WHERE key = 'schema_version'");_&&(n=parseInt(_.value,10))}}catch{}let o=[...O],c=o.filter(m=>!r.includes(m)),l=r.filter(m=>!o.includes(m)),h=c.length===0&&(n===void 0||n===1);return{needsMigration:!h,validation:{isValid:h,currentVersion:n,expectedVersion:1,missingColumns:c,extraColumns:l,message:h?void 0:"Schema mismatch detected"},dbPath:a,exists:!0}}finally{Y(t)}}async function z(a){let{dbPath:e,backup:t=!0,dryRun:s=!1,verbose:i=!1}=a,r=[],n=d=>{i&&console.log(`[migrate] ${d}`),r.push(d)};if(!N.default.existsSync(e))return{success:!1,fromVersion:null,toVersion:1,changes:["Database file does not exist"],error:`Database file not found: ${e}`};let o=await L(e);if(!o.needsMigration)return n("Schema is already up to date"),{success:!0,fromVersion:o.validation.currentVersion??1,toVersion:1,changes:r};let c=o.validation.currentVersion??0,l;if(t&&!s&&(l=`${e}.backup.${Date.now()}`,N.default.copyFileSync(e,l),n(`Created backup at: ${l}`)),s)return n("DRY RUN - No changes will be made"),n(`Would migrate from v${c} to v${1}`),o.validation.missingColumns.length>0&&n(`Would add columns: ${o.validation.missingColumns.join(", ")}`),{success:!0,fromVersion:c,toVersion:1,changes:r};let h=await Q(e);try{A(h,"BEGIN TRANSACTION");for(let d of o.validation.missingColumns){let m=ce(d),_=oe(d);n(`Adding column: ${d} (${_})`),A(h,`ALTER TABLE kv_store ADD COLUMN ${d} ${_} ${m}`)}return n("Creating/updating indexes"),A(h,`
CREATE INDEX IF NOT EXISTS idx_kv_ns_active
ON kv_store(namespace, is_deleted, expires_at, key)
WHERE is_deleted = 0;
CREATE INDEX IF NOT EXISTS idx_kv_global_active
ON kv_store(is_deleted, expires_at, namespace, key)
WHERE is_deleted = 0;
CREATE INDEX IF NOT EXISTS idx_kv_ns_lru
ON kv_store(namespace, last_accessed)
WHERE is_deleted = 0;
CREATE INDEX IF NOT EXISTS idx_kv_expiry
ON kv_store(expires_at)
WHERE is_deleted = 0 AND expires_at < ${9007199254740991};
CREATE INDEX IF NOT EXISTS idx_kv_ns_stats
ON kv_store(namespace, is_deleted);
`),n("Updating schema version"),A(h,`
CREATE TABLE IF NOT EXISTS yq_meta (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
INSERT OR REPLACE INTO yq_meta (key, value) VALUES ('schema_version', '${1}');
`),A(h,"COMMIT"),n(`Migration complete: v${c} -> v${1}`),{success:!0,fromVersion:c,toVersion:1,changes:r,backupPath:l}}catch(d){try{A(h,"ROLLBACK")}catch{}let m=d instanceof Error?d.message:String(d);return n(`Migration failed: ${m}`),{success:!1,fromVersion:c,toVersion:1,changes:r,backupPath:l,error:m}}finally{Y(h)}}function oe(a){switch(a){case"namespace":case"key":return"TEXT NOT NULL";case"value":return"BLOB NOT NULL";case"created_at":case"expires_at":case"last_accessed":return"INTEGER NOT NULL";case"is_deleted":return"INTEGER NOT NULL";default:return"TEXT"}}function ce(a){switch(a){case"namespace":return`DEFAULT '${b}'`;case"expires_at":return`DEFAULT ${9007199254740991}`;case"is_deleted":return"DEFAULT 0";case"last_accessed":return"DEFAULT 0";case"created_at":return`DEFAULT ${Date.now()}`;default:return""}}function F(a,e="*.yqs"){let t=[];if(!N.default.existsSync(a))return t;let s=N.default.readdirSync(a),i=new RegExp("^"+e.replace(/\*/g,".*").replace(/\?/g,".")+"$");for(let r of s)i.test(r)&&t.push(G.default.join(a,r));return t}var G,N,M=W(()=>{"use strict";G=E(require("node:path"),1),N=E(require("node:fs"),1);v()});var me={};H(me,{BaseStorageEngine:()=>y,BunStorageEngine:()=>f,DEFAULT_NAMESPACE:()=>b,NEVER_EXPIRES:()=>p,NodeStorageEngine:()=>S,SCHEMA_VERSION:()=>u,SchemaMismatchError:()=>g,TypedEventEmitter:()=>T,YqStore:()=>k,checkSchema:()=>L,createStorageEngine:()=>x,createStorageEngineOfType:()=>X,default:()=>k,findDatabases:()=>F,migrate:()=>z});module.exports=ne(me);function D(){process.env.NODE_NO_WARNINGS="1",process.removeAllListeners("warning"),process.on("warning",e=>{e.name==="ExperimentalWarning"&&e.message.includes("SQLite is an experimental feature")||e.message.includes("ExperimentalWarning")});let a=process.emitWarning;process.emitWarning=function(e,...t){let s=typeof e=="string"?e:e.message;if(!(s.includes("ExperimentalWarning")&&s.includes("SQLite")||s.includes("ExperimentalWarning")))return a.call(this,e,...t)}}D();var j=E(require("node:os"),1),J=E(require("node:crypto"),1);var V=require("node:events"),T=class{emitter=new V.EventEmitter;addEventListener(e,t){return this.emitter.on(e,t),this}on(e,t){return this.addEventListener(e,t)}removeEventListener(e,t){return this.emitter.removeListener(e,t),this}off(e,t){return this.removeEventListener(e,t)}emit(e,...t){return this.emitter.emit(e,...t)}};v();var g=class a extends Error{validationResult;constructor(e){let t=a.buildMessage(e);super(t),this.name="SchemaMismatchError",this.validationResult=e}static buildMessage(e){let t=["","\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557","\u2551 SCHEMA MIGRATION REQUIRED \u2551","\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D","",`Your database schema (v${e.currentVersion??"unknown"}) is incompatible with the current version (v${e.expectedVersion}).`,""];return e.missingColumns.length>0&&t.push(`Missing columns: ${e.missingColumns.join(", ")}`),e.extraColumns.length>0&&t.push(`Unknown columns: ${e.extraColumns.join(", ")}`),t.push("","To migrate your database, run:",""," npx yqstore migrate","","Or with Bun:",""," bunx yqstore migrate","","For more options (backup, dry-run, etc.):",""," npx yqstore migrate --help",""),t.join(`
`)}},y=class{config;emitter;isInitialized=!1;metrics={operations:{get:{count:0,totalMs:0},set:{count:0,totalMs:0},delete:{count:0,totalMs:0},has:{count:0,totalMs:0}},cache:{hits:0,misses:0},errors:{count:0}};constructor(e,t){this.emitter=t,this.config={dbDir:e.dbDir,dbName:e.dbName,inMemory:e.inMemory??!1,dbFileName:e.dbFileName??`${e.dbName}.yqs`,softDelete:e.softDelete??!0,trackLRU:e.trackLRU??!0,maxEntries:e.maxEntries??1e6,sqlite:{journalMode:e.sqlite?.journalMode??"WAL",synchronous:e.sqlite?.synchronous??"NORMAL",cacheSize:e.sqlite?.cacheSize??-64e3,tempStore:e.sqlite?.tempStore??"memory",busyTimeout:e.sqlite?.busyTimeout??5e3,mmapSize:e.sqlite?.mmapSize??268435456},debug:e.debug??!1,keepAlive:e.keepAlive??!1}}ensureInitialized(){if(!this.isInitialized)throw new Error("Storage engine not initialized. Call initialize() first.")}now(){return Date.now()}calculateExpiresAt(e){return!e||e<=0?9007199254740991:this.now()+e*1e3}normalizeNamespace(e){return e||b}serialize(e){let t=JSON.stringify(e);return new TextEncoder().encode(t)}deserialize(e){let t=new TextDecoder().decode(e);return JSON.parse(t)}trackMetric(e,t){this.metrics.operations[e].count++,this.metrics.operations[e].totalMs+=t}trackCacheHit(e){e?this.metrics.cache.hits++:this.metrics.cache.misses++}trackError(e){this.metrics.errors.count++,this.metrics.errors.lastError=e}getMetrics(){return{...this.metrics}}resetMetrics(){this.metrics={operations:{get:{count:0,totalMs:0},set:{count:0,totalMs:0},delete:{count:0,totalMs:0},has:{count:0,totalMs:0}},cache:{hits:0,misses:0},errors:{count:0}}}debug(e,...t){this.config.debug&&console.log(`[StorageEngine] ${e}`,...t)}isBunRuntime(){return typeof Bun<"u"&&!!Bun?.version}validateSchema(e,t){let s=[...O],i=s.filter(o=>!e.includes(o)),r=e.filter(o=>!s.includes(o)),n=i.length===0&&(t===void 0||t===1);return{isValid:n,currentVersion:t,expectedVersion:1,missingColumns:i,extraColumns:r,message:n?void 0:"Schema mismatch detected"}}getTableExistsSQL(){return"SELECT name FROM sqlite_master WHERE type='table' AND name='kv_store'"}getTableInfoSQL(){return"PRAGMA table_info(kv_store)"}getSchemaVersionTableSQL(){return`
CREATE TABLE IF NOT EXISTS yq_meta (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
INSERT OR REPLACE INTO yq_meta (key, value) VALUES ('schema_version', '${1}');
`}getSchemaVersionSQL(){return"SELECT value FROM yq_meta WHERE key = 'schema_version'"}getCreateTableSQL(){return`
CREATE TABLE IF NOT EXISTS kv_store (
namespace TEXT NOT NULL DEFAULT '${b}',
key TEXT NOT NULL,
value BLOB NOT NULL,
created_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL DEFAULT ${9007199254740991},
is_deleted INTEGER NOT NULL DEFAULT 0,
last_accessed INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (namespace, key)
) WITHOUT ROWID;
-- Namespace-scoped active records (main query pattern)
CREATE INDEX IF NOT EXISTS idx_kv_ns_active
ON kv_store(namespace, is_deleted, expires_at, key)
WHERE is_deleted = 0;
-- Global active records (cross-namespace queries)
CREATE INDEX IF NOT EXISTS idx_kv_global_active
ON kv_store(is_deleted, expires_at, namespace, key)
WHERE is_deleted = 0;
-- LRU per namespace
CREATE INDEX IF NOT EXISTS idx_kv_ns_lru
ON kv_store(namespace, last_accessed)
WHERE is_deleted = 0;
-- Expiration cleanup
CREATE INDEX IF NOT EXISTS idx_kv_expiry
ON kv_store(expires_at)
WHERE is_deleted = 0 AND expires_at < ${9007199254740991};
-- Namespace stats
CREATE INDEX IF NOT EXISTS idx_kv_ns_stats
ON kv_store(namespace, is_deleted);
`}getPragmaSQL(){let e=this.config.sqlite,t=[];return this.config.inMemory?t.push("PRAGMA journal_mode = MEMORY;","PRAGMA synchronous = OFF;","PRAGMA cache_size = 10000;","PRAGMA temp_store = MEMORY;"):t.push(`PRAGMA journal_mode = ${e.journalMode};`,`PRAGMA synchronous = ${e.synchronous};`,`PRAGMA cache_size = ${e.cacheSize};`,`PRAGMA temp_store = ${e.tempStore};`,`PRAGMA mmap_size = ${e.mmapSize};`,"PRAGMA page_size = 4096;","PRAGMA auto_vacuum = INCREMENTAL;"),t.push(`PRAGMA busy_timeout = ${e.busyTimeout};`),t}};var C=E(require("node:path"),1),q=E(require("node:fs/promises"),1);v();var f=class extends y{db;statements;dbFilePath;pendingAccessUpdates=new Map;accessFlushTimer;constructor(e,t){super(e,t),this.config.inMemory?this.dbFilePath=":memory:":this.dbFilePath=C.default.resolve(this.config.dbDir,this.config.dbFileName)}async initialize(){if(this.isInitialized)return;this.config.inMemory||await q.default.mkdir(C.default.dirname(this.dbFilePath),{recursive:!0});let{Database:e}=await import("bun:sqlite");this.db=new e(this.dbFilePath);for(let s of this.getPragmaSQL())this.db.exec(s);if(this.db.query(this.getTableExistsSQL()).get()){let i=this.db.query(this.getTableInfoSQL()).all().map(o=>o.name),r;try{if(this.db.query("SELECT name FROM sqlite_master WHERE type='table' AND name='yq_meta'").get()){let c=this.db.query(this.getSchemaVersionSQL()).get();c&&(r=parseInt(c.value,10))}}catch{}let n=this.validateSchema(i,r);if(!n.isValid)throw this.db.close(),this.db=void 0,new g(n);this.debug("Existing schema validated successfully")}this.db.exec(this.getCreateTableSQL()),this.db.exec(this.getSchemaVersionTableSQL()),this.prepareStatements(),this.config.trackLRU&&(this.accessFlushTimer=setInterval(()=>{this.flushAccessUpdates()},1e3),!this.config.keepAlive&&this.accessFlushTimer.unref&&this.accessFlushTimer.unref()),this.isInitialized=!0,this.debug("Initialized BunStorageEngine")}prepareStatements(){if(!this.db)throw new Error("Database not initialized");let e=this.now();this.statements={get:this.db.prepare(`
SELECT namespace, key, value, created_at, expires_at, is_deleted, last_accessed
FROM kv_store
WHERE namespace = ? AND key = ? AND is_deleted = 0 AND expires_at > ?
`),set:this.db.prepare(`
INSERT OR REPLACE INTO kv_store
(namespace, key, value, created_at, expires_at, is_deleted, last_accessed)
VALUES (?, ?, ?, ?, ?, 0, ?)
`),delete:this.db.prepare(`
DELETE FROM kv_store WHERE namespace = ? AND key = ?
`),softDelete:this.db.prepare(`
UPDATE kv_store SET is_deleted = 1 WHERE namespace = ? AND key = ? AND is_deleted = 0
`),has:this.db.prepare(`
SELECT 1 FROM kv_store
WHERE namespace = ? AND key = ? AND is_deleted = 0 AND expires_at > ?
LIMIT 1
`),updateAccess:this.db.prepare(`
UPDATE kv_store SET last_accessed = ? WHERE namespace = ? AND key = ?
`),countActive:this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE is_deleted = 0 AND expires_at > ?
`),countActiveByNamespace:this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE namespace = ? AND is_deleted = 0 AND expires_at > ?
`),countDeleted:this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store WHERE is_deleted = 1
`),countExpired:this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE is_deleted = 0 AND expires_at <= ? AND expires_at < ${9007199254740991}
`),countAll:this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
`),deleteExpired:this.db.prepare(`
DELETE FROM kv_store
WHERE is_deleted = 0 AND expires_at <= ? AND expires_at < ${9007199254740991}
`),deleteDeleted:this.db.prepare(`
DELETE FROM kv_store WHERE is_deleted = 1
`),deleteNamespace:this.db.prepare(`
DELETE FROM kv_store WHERE namespace = ?
`),softDeleteNamespace:this.db.prepare(`
UPDATE kv_store SET is_deleted = 1 WHERE namespace = ? AND is_deleted = 0
`),deleteAll:this.db.prepare(`
DELETE FROM kv_store
`),softDeleteAll:this.db.prepare(`
UPDATE kv_store SET is_deleted = 1 WHERE is_deleted = 0
`),selectLRU:this.db.prepare(`
SELECT namespace, key FROM kv_store
WHERE is_deleted = 0
ORDER BY last_accessed ASC
LIMIT ?
`),deleteLRU:this.db.prepare(`
DELETE FROM kv_store WHERE namespace = ? AND key = ?
`),listNamespaces:this.db.prepare(`
SELECT DISTINCT namespace FROM kv_store
WHERE is_deleted = 0 AND expires_at > ?
ORDER BY namespace
`)}}async close(){if(this.flushAccessUpdates(),this.accessFlushTimer&&(clearInterval(this.accessFlushTimer),this.accessFlushTimer=void 0),this.db){try{this.db.close()}catch(e){this.debug("Error closing database:",e)}this.db=void 0,this.statements=void 0}this.isInitialized=!1,this.emitter.emit("close")}async set(e,t,s,i){this.ensureInitialized();let r=performance.now(),n=this.normalizeNamespace(i),o=this.now(),c=this.calculateExpiresAt(s),l=this.serialize(t);this.statements.set.run(n,e,l,o,c,o),this.trackMetric("set",performance.now()-r),this.emitter.emit("set",e,t)}async get(e,t){this.ensureInitialized();let s=performance.now(),i=this.normalizeNamespace(t),r=this.now(),n=this.statements.get.get(i,e,r);return n?(this.config.trackLRU&&this.queueAccessUpdate(i,e,r),this.trackMetric("get",performance.now()-s),this.trackCacheHit(!0),{key:n.key,namespace:n.namespace,value:this.deserialize(n.value),createdAt:n.created_at,expiresAt:n.expires_at<9007199254740991?n.expires_at:void 0,isDeleted:!1,lastAccessed:n.last_accessed}):(this.trackMetric("get",performance.now()-s),this.trackCacheHit(!1),null)}async delete(e,t){this.ensureInitialized();let s=performance.now(),i=this.normalizeNamespace(t),r;this.config.softDelete?r=this.statements.softDelete.run(i,e):r=this.statements.delete.run(i,e);let n=r.changes>0;return this.trackMetric("delete",performance.now()-s),n&&this.emitter.emit("delete",e),n}async has(e,t){this.ensureInitialized();let s=performance.now(),i=this.normalizeNamespace(t),r=this.now(),n=this.statements.has.get(i,e,r);return this.trackMetric("has",performance.now()-s),n!==null}async getMany(e,t){this.ensureInitialized();let s=this.normalizeNamespace(t),i=this.now(),r=new Map;if(e.length===0)return r;let n=e.map(()=>"?").join(", "),c=this.db.prepare(`
SELECT key, value FROM kv_store
WHERE namespace = ? AND key IN (${n})
AND is_deleted = 0 AND expires_at > ?
`).all(s,...e,i);for(let l of c)r.set(l.key,this.deserialize(l.value));if(this.config.trackLRU)for(let l of r.keys())this.queueAccessUpdate(s,l,i);return r}async setMany(e,t){if(this.ensureInitialized(),e.length===0)return;let s=this.normalizeNamespace(t),i=this.now();this.db.transaction(()=>{for(let n of e){let o=this.calculateExpiresAt(n.ttl),c=this.serialize(n.value);this.statements.set.run(s,n.key,c,i,o,i)}})();for(let n of e)this.emitter.emit("set",n.key,n.value)}async deleteMany(e,t){if(this.ensureInitialized(),e.length===0)return 0;let s=this.normalizeNamespace(t),i=0;return this.db.transaction(()=>{for(let n of e){let o;this.config.softDelete?o=this.statements.softDelete.run(s,n):o=this.statements.delete.run(s,n),o.changes>0&&(i++,this.emitter.emit("delete",n))}})(),i}async batch(e){if(this.ensureInitialized(),e.length===0)return;let t=this.now();this.db.transaction(()=>{for(let i of e){let r=this.normalizeNamespace(i.namespace);if(i.type==="put"){let n=this.calculateExpiresAt(i.ttl),o=this.serialize(i.value);this.statements.set.run(r,i.key,o,t,n,t),this.emitter.emit("set",i.key,i.value)}else i.type==="del"&&(this.config.softDelete?this.statements.softDelete.run(r,i.key):this.statements.delete.run(r,i.key),this.emitter.emit("delete",i.key))}})()}async listKeys(e){this.ensureInitialized();let t=this.now(),s=e?.namespace,i=e?.prefix,r=e?.suffix,n=e?.limit??1e3,o=e?.offset??0,c=`
SELECT key FROM kv_store
WHERE is_deleted = 0 AND expires_at > ?
`,l=[t];return s&&(c+=" AND namespace = ?",l.push(s)),i&&(c+=" AND key LIKE ?",l.push(i+"%")),r&&(c+=" AND key LIKE ?",l.push("%"+r)),c+=" ORDER BY key LIMIT ? OFFSET ?",l.push(n,o),this.db.prepare(c).all(...l).map(m=>m.key)}async listEntries(e){this.ensureInitialized();let t=this.now(),s=e?.namespace,i=e?.prefix,r=e?.suffix,n=e?.limit??100,o=e?.offset??0,c=`
SELECT namespace, key, value, created_at, expires_at, is_deleted, last_accessed
FROM kv_store
WHERE is_deleted = 0 AND expires_at > ?
`,l=[t];return s&&(c+=" AND namespace = ?",l.push(s)),i&&(c+=" AND key LIKE ?",l.push(i+"%")),r&&(c+=" AND key LIKE ?",l.push("%"+r)),c+=" ORDER BY key LIMIT ? OFFSET ?",l.push(n,o),this.db.prepare(c).all(...l).map(m=>({key:m.key,namespace:m.namespace,value:this.deserialize(m.value),createdAt:m.created_at,expiresAt:m.expires_at<9007199254740991?m.expires_at:void 0,isDeleted:!1,lastAccessed:m.last_accessed}))}async getSize(e,t){this.ensureInitialized();let s=this.now(),i=t?.namespace,r=e??"active",n;if(i)switch(r){case"active":n=this.statements.countActiveByNamespace.get(i,s);break;case"deleted":n=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store WHERE namespace = ? AND is_deleted = 1
`).get(i);break;case"expired":n=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE namespace = ? AND is_deleted = 0 AND expires_at <= ? AND expires_at < ${9007199254740991}
`).get(i,s);break;case"all":n=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store WHERE namespace = ?
`).get(i);break}else switch(r){case"active":n=this.statements.countActive.get(s);break;case"deleted":n=this.statements.countDeleted.get();break;case"expired":n=this.statements.countExpired.get(s);break;case"all":n=this.statements.countAll.get();break}return n?.count??0}async clearExpired(){this.ensureInitialized();let e=this.now(),t=this.db.prepare(`
SELECT key FROM kv_store
WHERE is_deleted = 0 AND expires_at <= ? AND expires_at < ${9007199254740991}
`).all(e),s=this.statements.deleteExpired.run(e);for(let i of t)this.emitter.emit("expire",i.key);return s.changes}async clearDeleted(){return this.ensureInitialized(),this.statements.deleteDeleted.run().changes}async clearNamespace(e){this.ensureInitialized();let t;return this.config.softDelete?t=this.statements.softDeleteNamespace.run(e):t=this.statements.deleteNamespace.run(e),t.changes}async clearAll(){this.ensureInitialized(),this.config.softDelete?this.statements.softDeleteAll.run():this.statements.deleteAll.run()}queueAccessUpdate(e,t,s){let i=`${e}:${t}`;this.pendingAccessUpdates.set(i,s),this.pendingAccessUpdates.size>=100&&this.flushAccessUpdates()}flushAccessUpdates(){if(!this.db||!this.statements||this.pendingAccessUpdates.size===0)return;let e=Array.from(this.pendingAccessUpdates.entries());this.pendingAccessUpdates.clear();try{this.db.transaction(()=>{for(let[s,i]of e){let[r,...n]=s.split(":"),o=n.join(":");this.statements.updateAccess.run(i,r,o)}})()}catch(t){this.debug("Error flushing access updates:",t)}}async evictLRU(e){this.ensureInitialized();let t=e??this.config.maxEntries,s=await this.getSize("active");if(s<=t)return 0;let i=s-t,r=this.statements.selectLRU.all(i);return this.db.transaction(()=>{for(let o of r)this.statements.deleteLRU.run(o.namespace,o.key),this.emitter.emit("evict",o.key)})(),r.length}async listNamespaces(){this.ensureInitialized();let e=this.now();return this.statements.listNamespaces.all(e).map(s=>s.namespace)}async getNamespaceStats(e){this.ensureInitialized();let t=this.now(),s=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE namespace = ? AND is_deleted = 0 AND expires_at > ?
`).get(e,t),i=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE namespace = ? AND is_deleted = 1
`).get(e),r=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE namespace = ? AND is_deleted = 0 AND expires_at <= ? AND expires_at < ${9007199254740991}
`).get(e,t),n=this.db.prepare(`
SELECT COALESCE(SUM(LENGTH(value)), 0) as size FROM kv_store
WHERE namespace = ? AND is_deleted = 0 AND expires_at > ?
`).get(e,t);return{namespace:e,activeCount:s?.count??0,deletedCount:i?.count??0,expiredCount:r?.count??0,sizeBytes:n?.size??0}}getDbFilePath(){return this.dbFilePath}};var I=E(require("node:path"),1),$=E(require("node:fs/promises"),1);v();var S=class extends y{db;statements;dbFilePath;pendingAccessUpdates=new Map;accessFlushTimer;constructor(e,t){super(e,t),this.config.inMemory?this.dbFilePath=":memory:":this.dbFilePath=I.default.resolve(this.config.dbDir,this.config.dbFileName)}async initialize(){if(this.isInitialized)return;this.config.inMemory||await $.default.mkdir(I.default.dirname(this.dbFilePath),{recursive:!0});let{DatabaseSync:e}=await import("node:sqlite");this.db=new e(this.dbFilePath);for(let i of this.getPragmaSQL())this.db.exec(i);if(this.db.prepare(this.getTableExistsSQL()).get()){let n=this.db.prepare(this.getTableInfoSQL()).all().map(l=>l.name),o;try{if(this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='yq_meta'").get()){let m=this.db.prepare(this.getSchemaVersionSQL()).get();m&&(o=parseInt(m.value,10))}}catch{}let c=this.validateSchema(n,o);if(!c.isValid)throw this.db.close(),this.db=void 0,new g(c);this.debug("Existing schema validated successfully")}this.db.exec(this.getCreateTableSQL()),this.db.exec(this.getSchemaVersionTableSQL()),this.prepareStatements(),this.config.trackLRU&&(this.accessFlushTimer=setInterval(()=>{this.flushAccessUpdates()},1e3),!this.config.keepAlive&&this.accessFlushTimer.unref&&this.accessFlushTimer.unref()),this.isInitialized=!0,this.debug("Initialized NodeStorageEngine")}prepareStatements(){if(!this.db)throw new Error("Database not initialized");this.statements={get:this.db.prepare(`
SELECT namespace, key, value, created_at, expires_at, is_deleted, last_accessed
FROM kv_store
WHERE namespace = ? AND key = ? AND is_deleted = 0 AND expires_at > ?
`),set:this.db.prepare(`
INSERT OR REPLACE INTO kv_store
(namespace, key, value, created_at, expires_at, is_deleted, last_accessed)
VALUES (?, ?, ?, ?, ?, 0, ?)
`),delete:this.db.prepare(`
DELETE FROM kv_store WHERE namespace = ? AND key = ?
`),softDelete:this.db.prepare(`
UPDATE kv_store SET is_deleted = 1 WHERE namespace = ? AND key = ? AND is_deleted = 0
`),has:this.db.prepare(`
SELECT 1 FROM kv_store
WHERE namespace = ? AND key = ? AND is_deleted = 0 AND expires_at > ?
LIMIT 1
`),updateAccess:this.db.prepare(`
UPDATE kv_store SET last_accessed = ? WHERE namespace = ? AND key = ?
`),countActive:this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE is_deleted = 0 AND expires_at > ?
`),countActiveByNamespace:this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE namespace = ? AND is_deleted = 0 AND expires_at > ?
`),countDeleted:this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store WHERE is_deleted = 1
`),countExpired:this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE is_deleted = 0 AND expires_at <= ? AND expires_at < ${9007199254740991}
`),countAll:this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
`),deleteExpired:this.db.prepare(`
DELETE FROM kv_store
WHERE is_deleted = 0 AND expires_at <= ? AND expires_at < ${9007199254740991}
`),deleteDeleted:this.db.prepare(`
DELETE FROM kv_store WHERE is_deleted = 1
`),deleteNamespace:this.db.prepare(`
DELETE FROM kv_store WHERE namespace = ?
`),softDeleteNamespace:this.db.prepare(`
UPDATE kv_store SET is_deleted = 1 WHERE namespace = ? AND is_deleted = 0
`),deleteAll:this.db.prepare(`
DELETE FROM kv_store
`),softDeleteAll:this.db.prepare(`
UPDATE kv_store SET is_deleted = 1 WHERE is_deleted = 0
`),selectLRU:this.db.prepare(`
SELECT namespace, key FROM kv_store
WHERE is_deleted = 0
ORDER BY last_accessed ASC
LIMIT ?
`),deleteLRU:this.db.prepare(`
DELETE FROM kv_store WHERE namespace = ? AND key = ?
`),listNamespaces:this.db.prepare(`
SELECT DISTINCT namespace FROM kv_store
WHERE is_deleted = 0 AND expires_at > ?
ORDER BY namespace
`)}}async close(){if(this.flushAccessUpdates(),this.accessFlushTimer&&(clearInterval(this.accessFlushTimer),this.accessFlushTimer=void 0),this.db){try{this.db.close()}catch(e){this.debug("Error closing database:",e)}this.db=void 0,this.statements=void 0}this.isInitialized=!1,this.emitter.emit("close")}async set(e,t,s,i){this.ensureInitialized();let r=performance.now(),n=this.normalizeNamespace(i),o=this.now(),c=this.calculateExpiresAt(s),l=this.serialize(t);this.statements.set.run(n,e,l,o,c,o),this.trackMetric("set",performance.now()-r),this.emitter.emit("set",e,t)}async get(e,t){this.ensureInitialized();let s=performance.now(),i=this.normalizeNamespace(t),r=this.now(),n=this.statements.get.get(i,e,r);return n?(this.config.trackLRU&&this.queueAccessUpdate(i,e,r),this.trackMetric("get",performance.now()-s),this.trackCacheHit(!0),{key:n.key,namespace:n.namespace,value:this.deserialize(n.value),createdAt:n.created_at,expiresAt:n.expires_at<9007199254740991?n.expires_at:void 0,isDeleted:!1,lastAccessed:n.last_accessed}):(this.trackMetric("get",performance.now()-s),this.trackCacheHit(!1),null)}async delete(e,t){this.ensureInitialized();let s=performance.now(),i=this.normalizeNamespace(t),r;this.config.softDelete?r=this.statements.softDelete.run(i,e).changes:r=this.statements.delete.run(i,e).changes;let n=r>0;return this.trackMetric("delete",performance.now()-s),n&&this.emitter.emit("delete",e),n}async has(e,t){this.ensureInitialized();let s=performance.now(),i=this.normalizeNamespace(t),r=this.now(),n=this.statements.has.get(i,e,r);return this.trackMetric("has",performance.now()-s),n!==void 0}async getMany(e,t){this.ensureInitialized();let s=this.normalizeNamespace(t),i=this.now(),r=new Map;if(e.length===0)return r;let n=e.map(()=>"?").join(", "),c=this.db.prepare(`
SELECT key, value FROM kv_store
WHERE namespace = ? AND key IN (${n})
AND is_deleted = 0 AND expires_at > ?
`).all(s,...e,i);for(let l of c)r.set(l.key,this.deserialize(l.value));if(this.config.trackLRU)for(let l of r.keys())this.queueAccessUpdate(s,l,i);return r}async setMany(e,t){if(this.ensureInitialized(),e.length===0)return;let s=this.normalizeNamespace(t),i=this.now();this.db.exec("BEGIN TRANSACTION");try{for(let r of e){let n=this.calculateExpiresAt(r.ttl),o=this.serialize(r.value);this.statements.set.run(s,r.key,o,i,n,i)}this.db.exec("COMMIT");for(let r of e)this.emitter.emit("set",r.key,r.value)}catch(r){throw this.db.exec("ROLLBACK"),r}}async deleteMany(e,t){if(this.ensureInitialized(),e.length===0)return 0;let s=this.normalizeNamespace(t),i=0;this.db.exec("BEGIN TRANSACTION");try{for(let r of e){let n;this.config.softDelete?n=this.statements.softDelete.run(s,r).changes:n=this.statements.delete.run(s,r).changes,n>0&&i++}this.db.exec("COMMIT");for(let r of e)this.emitter.emit("delete",r)}catch(r){throw this.db.exec("ROLLBACK"),r}return i}async batch(e){if(this.ensureInitialized(),e.length===0)return;let t=this.now();this.db.exec("BEGIN TRANSACTION");try{for(let s of e){let i=this.normalizeNamespace(s.namespace);if(s.type==="put"){let r=this.calculateExpiresAt(s.ttl),n=this.serialize(s.value);this.statements.set.run(i,s.key,n,t,r,t)}else s.type==="del"&&(this.config.softDelete?this.statements.softDelete.run(i,s.key):this.statements.delete.run(i,s.key))}this.db.exec("COMMIT");for(let s of e)s.type==="put"?this.emitter.emit("set",s.key,s.value):this.emitter.emit("delete",s.key)}catch(s){throw this.db.exec("ROLLBACK"),s}}async listKeys(e){this.ensureInitialized();let t=this.now(),s=e?.namespace,i=e?.prefix,r=e?.suffix,n=e?.limit??1e3,o=e?.offset??0,c=`
SELECT key FROM kv_store
WHERE is_deleted = 0 AND expires_at > ?
`,l=[t];return s&&(c+=" AND namespace = ?",l.push(s)),i&&(c+=" AND key LIKE ?",l.push(i+"%")),r&&(c+=" AND key LIKE ?",l.push("%"+r)),c+=" ORDER BY key LIMIT ? OFFSET ?",l.push(n,o),this.db.prepare(c).all(...l).map(m=>m.key)}async listEntries(e){this.ensureInitialized();let t=this.now(),s=e?.namespace,i=e?.prefix,r=e?.suffix,n=e?.limit??100,o=e?.offset??0,c=`
SELECT namespace, key, value, created_at, expires_at, is_deleted, last_accessed
FROM kv_store
WHERE is_deleted = 0 AND expires_at > ?
`,l=[t];return s&&(c+=" AND namespace = ?",l.push(s)),i&&(c+=" AND key LIKE ?",l.push(i+"%")),r&&(c+=" AND key LIKE ?",l.push("%"+r)),c+=" ORDER BY key LIMIT ? OFFSET ?",l.push(n,o),this.db.prepare(c).all(...l).map(m=>({key:m.key,namespace:m.namespace,value:this.deserialize(m.value),createdAt:m.created_at,expiresAt:m.expires_at<9007199254740991?m.expires_at:void 0,isDeleted:!1,lastAccessed:m.last_accessed}))}async getSize(e,t){this.ensureInitialized();let s=this.now(),i=t?.namespace,r=e??"active",n;if(i)switch(r){case"active":n=this.statements.countActiveByNamespace.get(i,s);break;case"deleted":n=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store WHERE namespace = ? AND is_deleted = 1
`).get(i);break;case"expired":n=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE namespace = ? AND is_deleted = 0 AND expires_at <= ? AND expires_at < ${9007199254740991}
`).get(i,s);break;case"all":n=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store WHERE namespace = ?
`).get(i);break}else switch(r){case"active":n=this.statements.countActive.get(s);break;case"deleted":n=this.statements.countDeleted.get();break;case"expired":n=this.statements.countExpired.get(s);break;case"all":n=this.statements.countAll.get();break}return n?.count??0}async clearExpired(){this.ensureInitialized();let e=this.now(),t=this.db.prepare(`
SELECT key FROM kv_store
WHERE is_deleted = 0 AND expires_at <= ? AND expires_at < ${9007199254740991}
`).all(e),s=this.statements.deleteExpired.run(e);for(let i of t)this.emitter.emit("expire",i.key);return s.changes}async clearDeleted(){return this.ensureInitialized(),this.statements.deleteDeleted.run().changes}async clearNamespace(e){this.ensureInitialized();let t;return this.config.softDelete?t=this.statements.softDeleteNamespace.run(e).changes:t=this.statements.deleteNamespace.run(e).changes,t}async clearAll(){this.ensureInitialized(),this.config.softDelete?this.statements.softDeleteAll.run():this.statements.deleteAll.run()}queueAccessUpdate(e,t,s){let i=`${e}:${t}`;this.pendingAccessUpdates.set(i,s),this.pendingAccessUpdates.size>=100&&this.flushAccessUpdates()}flushAccessUpdates(){if(!this.db||!this.statements||this.pendingAccessUpdates.size===0)return;let e=Array.from(this.pendingAccessUpdates.entries());this.pendingAccessUpdates.clear();try{this.db.exec("BEGIN TRANSACTION");for(let[t,s]of e){let[i,...r]=t.split(":"),n=r.join(":");this.statements.updateAccess.run(s,i,n)}this.db.exec("COMMIT")}catch(t){try{this.db.exec("ROLLBACK")}catch{}this.debug("Error flushing access updates:",t)}}async evictLRU(e){this.ensureInitialized();let t=e??this.config.maxEntries,s=await this.getSize("active");if(s<=t)return 0;let i=s-t,r=this.statements.selectLRU.all(i);this.db.exec("BEGIN TRANSACTION");try{for(let n of r)this.statements.deleteLRU.run(n.namespace,n.key);this.db.exec("COMMIT");for(let n of r)this.emitter.emit("evict",n.key)}catch(n){throw this.db.exec("ROLLBACK"),n}return r.length}async listNamespaces(){this.ensureInitialized();let e=this.now();return this.statements.listNamespaces.all(e).map(s=>s.namespace)}async getNamespaceStats(e){this.ensureInitialized();let t=this.now(),s=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE namespace = ? AND is_deleted = 0 AND expires_at > ?
`).get(e,t),i=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE namespace = ? AND is_deleted = 1
`).get(e),r=this.db.prepare(`
SELECT COUNT(*) as count FROM kv_store
WHERE namespace = ? AND is_deleted = 0 AND expires_at <= ? AND expires_at < ${9007199254740991}
`).get(e,t),n=this.db.prepare(`
SELECT COALESCE(SUM(LENGTH(value)), 0) as size FROM kv_store
WHERE namespace = ? AND is_deleted = 0 AND expires_at > ?
`).get(e,t);return{namespace:e,activeCount:s?.count??0,deletedCount:i?.count??0,expiredCount:r?.count??0,sizeBytes:n?.size??0}}getDbFilePath(){return this.dbFilePath}};function re(){return typeof Bun<"u"&&!!Bun?.version}function x(a,e){return re()?new f(a,e):new S(a,e)}function X(a,e,t){switch(a){case"bun":return new f(e,t);case"node":return new S(e,t);default:return x(e,t)}}v();function le(a){return J.default.createHash("md5").update(a).digest("hex")}var B=class{constructor(e,t){this.name=e;this.store=t}async set(e,t,s){return this.store.set(e,t,{ttl:s,namespace:this.name})}async get(e){return this.store.get(e,{namespace:this.name})}async delete(e){return this.store.delete(e,{namespace:this.name})}async has(e){return this.store.has(e,{namespace:this.name})}async getMany(e){return this.store.getMany(e,{namespace:this.name})}async setMany(e){return this.store.setMany(e,{namespace:this.name})}async deleteMany(e){return this.store.deleteMany(e,{namespace:this.name})}async listKeys(e){return this.store.listKeys({...e,namespace:this.name})}async list(e){return this.store.list({...e,namespace:this.name})}async getSize(e){return e?this.store.getSize(e,{namespace:this.name}):this.store.getSize({namespace:this.name})}async clear(){return this.store.clearNamespace(this.name)}async getStats(){return this.store.getNamespaceStats(this.name)}},k=class a{options;emitter=new T;engine;namespaceCache=new Map;compactionTimer;evictionTimer;isCompacting=!1;isClosing=!1;dbName="store_storage";constructor(e){let t=j.default.tmpdir();e?.storage?.persistence?.dbDir?t=e.storage.persistence.dbDir:this.dbName=le(process.cwd())+"_"+this.dbName,e?.storage?.persistence?.dbFileName&&(this.dbName=e.storage.persistence.dbFileName),this.options={compactionInterval:e?.compactionInterval??36e5,ttl:e?.ttl??0,softDelete:e?.softDelete??!0,storage:{type:e?.storage?.type??"persistence",maxEntries:e?.storage?.maxEntries,maxMemory:e?.storage?.maxMemory,evictionInterval:e?.storage?.evictionInterval??6e4,eviction:e?.storage?.eviction??!1,persistence:e?.storage?.persistence},logging:e?.logging??{enabled:!1},debug:{enabled:e?.debug?.enabled??!1,timing:e?.debug?.timing??!1,sqlLogging:e?.debug?.sqlLogging??!1},keepAlive:e?.keepAlive??!1};let s={dbDir:t,dbName:this.dbName,dbFileName:`${this.dbName}.yqs`,inMemory:this.options.storage.type==="memory",softDelete:this.options.softDelete,trackLRU:this.options.storage.eviction??!0,maxEntries:this.options.storage.maxEntries??1e6,sqlite:this.options.storage.persistence?.sqlite,debug:this.options.debug.enabled,keepAlive:this.options.keepAlive};this.engine=x(s,this.emitter)}static async create(e){let t=new a(e);return await t.initialize(),t}async initialize(){try{await this.engine.initialize(),this.emitter.emit("db:ready"),await this.engine.clearExpired(),this.options.compactionInterval>0&&(this.compactionTimer=setInterval(()=>{this.compact().catch(()=>{})},this.options.compactionInterval),!this.options.keepAlive&&this.compactionTimer.unref&&this.compactionTimer.unref()),this.options.storage.eviction&&(this.evictionTimer=setInterval(()=>{this.runEviction().catch(()=>{})},this.options.storage.evictionInterval),!this.options.keepAlive&&this.evictionTimer.unref&&this.evictionTimer.unref()),this.emitter.emit("ready")}catch(e){throw this.emitter.emit("error",e),e}}on(e,t){return this.emitter.on(e,t),this}off(e,t){return this.emitter.off(e,t),this}addEventListener(e,t){return this.on(e,t)}removeEventListener(e,t){return this.off(e,t)}async has(e,t){return this.engine.has(e,t?.namespace)}async get(e,t){let s=await this.engine.get(e,t?.namespace);return s?s.value:null}async set(e,t,s){let i,r;typeof s=="number"?i=s:s&&(i=s.ttl,r=s.namespace),i===void 0&&this.options.ttl>0&&(i=this.options.ttl),await this.engine.set(e,t,i,r)}async delete(e,t){return this.engine.delete(e,t?.namespace)}async getMany(e,t){return this.engine.getMany(e,t?.namespace)}async setMany(e,t){return this.engine.setMany(e,t?.namespace)}async deleteMany(e,t){return this.engine.deleteMany(e,t?.namespace)}async getSize(e,t){return e===void 0?this.engine.getSize():typeof e=="string"?this.engine.getSize(e,t):this.engine.getSize("active",e)}async listKeys(e){return this.engine.listKeys(e)}async list(e){return(await this.engine.listEntries(e)).map(s=>({key:s.key,value:s.value}))}async forEach(e,t){let s=t?.limit??100,i=t?.offset??0;for(;;){let r=await this.engine.listEntries({...t,limit:s,offset:i});if(r.length===0)break;for(let n of r)await e(n.key,n.value);if(r.length<s)break;i+=s}}ns(e){let t=this.namespaceCache.get(e);return t||(t=new B(e,this),this.namespaceCache.set(e,t)),t}namespace(e){return this.ns(e)}async listNamespaces(){return this.engine.listNamespaces()}async clearNamespace(e){return this.engine.clearNamespace(e)}async getNamespaceStats(e){return this.engine.getNamespaceStats(e)}async getStats(){let e=await this.listNamespaces(),t=[],s=0,i=0,r=0,n=0;for(let o of e){let c=await this.getNamespaceStats(o);t.push(c),s+=c.activeCount,i+=c.deletedCount,r+=c.expiredCount,n+=c.sizeBytes}return{namespaces:t,totalActive:s,totalDeleted:i,totalExpired:r,totalSizeBytes:n}}getMetrics(){return this.engine.getMetrics()}resetMetrics(){this.engine.resetMetrics()}async clearSoftDeletedEntries(){return this.engine.clearDeleted()}async clearExpiredEntries(){return this.engine.clearExpired()}async clear(){return this.engine.clearAll()}async compact(){if(!(this.isCompacting||this.isClosing)){this.isCompacting=!0,this.emitter.emit("compact:start");try{let e=await this.engine.clearDeleted(),t=await this.engine.clearExpired();this.emitter.emit("compact:end",{newSize:await this.getSize(),keysProcessed:e+t})}catch(e){this.emitter.emit("error",e)}finally{this.isCompacting=!1}}}async runEviction(){if(!this.isClosing)try{await this.engine.clearExpired();let e=await this.engine.evictLRU();e>0&&this.emitter.emit("evict",e)}catch(e){this.emitter.emit("error",e)}}async batch(e){return this.engine.batch(e)}createTransaction(){let e=[],t=!1,s=!1;return{put(i,r,n,o){if(t||s)throw new Error("Transaction has already been committed or rolled back");e.push({type:"put",key:i,value:r,ttl:n,namespace:o})},del(i,r){if(t||s)throw new Error("Transaction has already been committed or rolled back");e.push({type:"del",key:i,namespace:r})},commit:async()=>{if(t||s)throw new Error("Transaction has already been committed or rolled back");await this.batch(e),t=!0},rollback(){if(t||s)throw new Error("Transaction has already been committed or rolled back");e.length=0,s=!0}}}async close(){this.isClosing=!0,this.compactionTimer&&(clearInterval(this.compactionTimer),this.compactionTimer=void 0),this.evictionTimer&&(clearInterval(this.evictionTimer),this.evictionTimer=void 0),await this.engine.close(),this.namespaceCache.clear()}getDbFilePath(){return this.engine.getDbFilePath()}static async checkSchema(e){let{checkSchema:t}=await Promise.resolve().then(()=>(M(),U));return t(e)}static async migrate(e){let{migrate:t}=await Promise.resolve().then(()=>(M(),U));return t(e)}static findDatabases(e,t="*.yqs"){let s=require("node:fs"),i=require("node:path"),r=[];if(!s.existsSync(e))return r;let n=s.readdirSync(e),o=new RegExp("^"+t.replace(/\*/g,".*").replace(/\?/g,".")+"$");for(let c of n)o.test(c)&&r.push(i.join(e,c));return r}};v();M();D();0&&(module.exports={BaseStorageEngine,BunStorageEngine,DEFAULT_NAMESPACE,NEVER_EXPIRES,NodeStorageEngine,SCHEMA_VERSION,SchemaMismatchError,TypedEventEmitter,YqStore,checkSchema,createStorageEngine,createStorageEngineOfType,findDatabases,migrate});
/**
* yq-store - A high-performance, zero-dependency, persistent Key-Value store for Node.js
*
* @author Olajide Mathew Ogundare <git@yuniq.solutions>
* @license MIT
*/