@joystick.js/db-canary 0.0.0-canary.2256 → 0.0.0-canary.2258

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{get_database as b}from"../query_engine.js";import{get_settings as x}from"../load_settings.js";import{get_write_queue as $}from"../write_queue.js";import{get_auth_stats as q}from"../auth_manager.js";import{get_query_statistics as F,get_auto_index_statistics as C,force_index_evaluation as E,remove_automatic_indexes as D}from"../auto_index_manager.js";import{create_index as O,drop_index as P,get_indexes as N}from"../index_manager.js";import{test_s3_connection as R,create_backup as j,list_backups as U,restore_backup as W,cleanup_old_backups as A}from"../backup_manager.js";import{get_replication_manager as w}from"../replication_manager.js";import{get_write_forwarder as J}from"../write_forwarder.js";import B from"../logger.js";import{performance_monitor as h}from"../performance_monitor.js";const{create_context_logger:y}=B("admin"),L=()=>{try{return x()}catch{return{port:1983}}},T=t=>{try{const e=t.getStats?t.getStats():{};return{pageSize:e.pageSize||0,treeDepth:e.treeDepth||0,treeBranchPages:e.treeBranchPages||0,treeLeafPages:e.treeLeafPages||0,entryCount:e.entryCount||0,mapSize:e.mapSize||0,lastPageNumber:e.lastPageNumber||0}}catch{return{error:"Could not retrieve database stats"}}},I=(t,e)=>{const r={};let s=0;try{for(const{key:n}of t.getRange())if(typeof n=="string"&&n.includes(":")&&!n.startsWith("_")){const a=n.split(":")[0];r[a]=(r[a]||0)+1,s++}}catch(n){e.warn("Could not iterate database range for stats",{error:n.message})}return{collections:r,total_documents:s}},G=()=>{const t=process.memoryUsage();return{rss:Math.round(t.rss/1024/1024),heapTotal:Math.round(t.heapTotal/1024/1024),heapUsed:Math.round(t.heapUsed/1024/1024),external:Math.round(t.external/1024/1024)}},H=t=>t.mapSize>0?Math.round(t.lastPageNumber*t.pageSize/t.mapSize*100):0,K=t=>({uptime:Math.floor(process.uptime()),uptime_formatted:v(process.uptime()),memory_usage:t,memory_usage_raw:process.memoryUsage(),node_version:process.version,platform:process.platform,arch:process.arch,pid:process.pid,cpu_usage:process.cpuUsage()}),Q=(t,e,r,s)=>({total_documents:t,total_collections:Object.keys(e).length,collections:e,stats:r,map_size_usage_percent:s,disk_usage:{map_size_mb:Math.round((r.mapSize||0)/1024/1024),used_space_mb:Math.round((r.lastPageNumber||0)*(r.pageSize||0)/1024/1024)}}),V=()=>{const t=y();try{const e=b(),r=L(),s=T(e),{collections:n,total_documents:a}=I(e,t),o=G(),c=H(s);return{server:K(o),database:Q(a,n,s,c),performance:{ops_per_second:M(),avg_response_time_ms:S()}}}catch(e){throw t.error("Failed to get enhanced stats",{error:e.message}),e}},v=t=>{const e=Math.floor(t/86400),r=Math.floor(t%86400/3600),s=Math.floor(t%3600/60),n=Math.floor(t%60);return e>0?`${e}d ${r}h ${s}m ${n}s`:r>0?`${r}h ${s}m ${n}s`:s>0?`${s}m ${n}s`:`${n}s`};let k=0,z=0,X=Date.now();const M=()=>{const t=(Date.now()-X)/1e3;return t>0?Math.round(k/t):0},S=()=>k>0?Math.round(z/k):0,Y=t=>{k++,z+=t},Z=t=>({name:t,document_count:0,indexes:[],estimated_size_bytes:0}),ee=(t,e,r)=>{const s={};let n=0;try{for(const{key:a}of t.getRange())if(typeof a=="string"&&a.includes(":")&&!a.startsWith("_")){const o=a.split(":");if(o.length>=3){const c=o[0],i=o[1];c===e&&(s[i]||(s[i]=Z(i)),s[i].document_count++,n++)}}}catch(a){r.warn("Could not iterate database range for collections",{error:a.message})}return{collections_map:s,total_documents:n}},te=(t,e,r)=>{const s=["admin_test","test_collection","queue_test","users","products","orders","sessions","logs","analytics","settings","another_collection","list_test","pagination_test","get_test","query_test","admin_insert_test","admin_update_test","admin_delete_test"];let n=0;for(const a of s)try{const o=`${e}:${a}:`,c=t.getRange({start:o,end:o+"\xFF"});let i=0;for(const _ of c)i++,n++;i>0&&(r[a]={name:a,document_count:i,indexes:[],estimated_size_bytes:i*100})}catch{continue}return n},re=(t,e,r,s)=>{try{const n=`index:${e}:`,a=t.getRange({start:n,end:n+"\xFF"});for(const{key:o,value:c}of a)if(typeof o=="string"&&o.startsWith(n)){const i=o.substring(n.length),_=i.split(":")[0],u=i.split(":")[1];r[_]&&u&&(r[_].indexes.includes(u)||r[_].indexes.push(u))}}catch(n){s.warn("Could not iterate index range",{error:n.message})}},oe=(t="default")=>{const e=y();try{const r=b();let{collections_map:s,total_documents:n}=ee(r,t,e);Object.keys(s).length===0&&(n+=te(r,t,s)),re(r,t,s,e);const a=Object.values(s);return{collections:a,total_collections:a.length,total_documents:n}}catch(r){throw e.error("Failed to list collections",{error:r.message}),r}},se=(t,e={})=>{const r=y();if(!t)throw new Error("Collection name is required");try{const s=b(),{limit:n=50,skip:a=0,sort_field:o,sort_order:c="asc",database:i="default"}=e,_=[],u=`${i}:${t}:`;let p=0,g=0;for(const{key:d,value:f}of s.getRange({start:u,end:u+"\xFF"}))if(typeof d=="string"&&d.startsWith(u)){if(g<a){g++;continue}if(p>=n)break;try{const l=JSON.parse(f),m=d.substring(u.length);_.push({_id:m,...l}),p++}catch(l){r.warn("Could not parse document",{collection:t,key:d,error:l.message})}}return o&&_.length>0&&_.sort((d,f)=>{const l=d[o],m=f[o];return c==="desc"?m>l?1:m<l?-1:0:l>m?1:l<m?-1:0}),{collection:t,documents:_,count:_.length,skip:a,limit:n,has_more:p===n}}catch(s){throw r.error("Failed to list documents",{collection:t,error:s.message}),s}},ne=(t,e,r="default")=>{const s=y();if(!t||!e)throw new Error("Collection name and document ID are required");try{const n=b(),a=`${r}:${t}:${e}`,o=n.get(a);if(!o)return{found:!1,collection:t,document_id:e};const c=JSON.parse(o);return{found:!0,collection:t,document_id:e,document:{_id:e,...c}}}catch(n){throw s.error("Failed to get document",{collection:t,document_id:e,error:n.message}),n}},ae=(t,e,r,s)=>{switch(t){case"$gt":return r>e;case"$gte":return r>=e;case"$lt":return r<e;case"$lte":return r<=e;case"$ne":return r!==e;case"$in":return Array.isArray(e)&&e.includes(r);case"$regex":const n=s.$options||"";return new RegExp(e,n).test(String(r));default:return r===s}},ce=(t,e)=>Object.keys(e).every(r=>{const s=e[r],n=t[r];return typeof s=="object"&&s!==null?Object.keys(s).every(a=>{const o=s[a];return ae(a,o,n,s)}):n===s}),ie=(t,e,r,s,n)=>{try{const a=JSON.parse(e),c={_id:t.substring(r.length),...a};return ce(c,s)?c:null}catch(a){return n.warn("Could not parse document during query",{key:t,error:a.message}),null}},_e=(t,e={},r={})=>{const s=y();if(!t)throw new Error("Collection name is required");try{const n=b(),{limit:a=100,skip:o=0,database:c="default"}=r,i=[],_=`${c}:${t}:`;let u=0,p=0,g=0;for(const{key:d,value:f}of n.getRange({start:_,end:_+"\xFF"}))if(typeof d=="string"&&d.startsWith(_)){g++;const l=ie(d,f,_,e,s);if(l){if(p<o){p++;continue}if(u>=a)break;i.push(l),u++}}return{collection:t,filter:e,documents:i,count:i.length,total_examined:g,skip:o,limit:a,has_more:u===a}}catch(n){throw s.error("Failed to query documents",{collection:t,filter:e,error:n.message}),n}},ue=async(t,e,r,s={})=>await(await import("./insert_one.js")).default(t,e,r,s),le=async(t,e,r,s,n={})=>await(await import("./update_one.js")).default(t,e,r,s,n),de=async(t,e,r,s={})=>await(await import("./delete_one.js")).default(t,e,r,s);var qe=async(t,e={},r,s)=>{const n=y(),a=Date.now();try{let o;switch(t){case"stats":o={server:{uptime:Math.floor(process.uptime()),uptime_formatted:v(process.uptime()),node_version:process.version,platform:process.platform,arch:process.arch,pid:process.pid},memory:h.get_memory_stats(),database:{...h.get_database_stats(),map_size_mb:Math.round((h.get_database_stats()?.map_size||0)/1024/1024),used_space_mb:Math.round((h.get_database_stats()?.used_space||0)/1024/1024),usage_percent:h.get_database_stats()?.usage_percent||0},performance:{ops_per_second:M(),avg_response_time_ms:S()},system:h.get_system_stats(),connections:r?.get_stats()||{},write_queue:$()?.get_stats()||{},authentication:{authenticated_clients:s?.size||0,...q()},settings:(()=>{try{return{port:x().port||1983}}catch{return{port:1983}}})()};break;case"list_collections":o=oe();break;case"list_documents":o=se(e.collection,{limit:e.limit,skip:e.skip,sort_field:e.sort_field,sort_order:e.sort_order});break;case"get_document":o=ne(e.collection,e.document_id);break;case"query_documents":o=_e(e.collection,e.filter,{limit:e.limit,skip:e.skip});break;case"insert_document":o=await ue(e.database||"default",e.collection,e.document,e.options);break;case"update_document":const i=e.document_id?{_id:e.document_id}:e.filter;o=await le(e.database||"default",e.collection,i,e.update,e.options);break;case"delete_document":const _=e.document_id?{_id:e.document_id}:e.filter;o=await de(e.database||"default",e.collection,_,e.options);break;case"test_s3_connection":o=await R();break;case"backup_now":o=await j();break;case"list_backups":o=await U();break;case"restore_backup":if(!e.backup_filename)throw new Error("backup_filename is required for restore operation");o=await W(e.backup_filename);break;case"cleanup_backups":o=await A();break;case"get_auto_index_stats":o=C();break;case"get_query_stats":o=F(e.collection);break;case"evaluate_auto_indexes":o=await E(e.collection);break;case"remove_auto_indexes":if(!e.collection)throw new Error("collection is required for remove_auto_indexes operation");o=await D(e.collection,e.field_names);break;case"create_index":if(!e.collection||!e.field)throw new Error("collection and field are required for create_index operation");o=await O(e.database||"default",e.collection,e.field,e.options);break;case"drop_index":if(!e.collection||!e.field)throw new Error("collection and field are required for drop_index operation");o=await P(e.database||"default",e.collection,e.field);break;case"get_indexes":if(!e.collection)throw new Error("collection is required for get_indexes operation");o={indexes:N(e.database||"default",e.collection)};break;case"get_replication_status":o=w().get_replication_status();break;case"add_secondary":if(!e.id||!e.ip||!e.port||!e.private_key)throw new Error("id, ip, port, and private_key are required for add_secondary operation");o=await w().add_secondary({id:e.id,ip:e.ip,port:e.port,private_key:e.private_key,enabled:!0});break;case"remove_secondary":if(!e.secondary_id)throw new Error("secondary_id is required for remove_secondary operation");o=w().remove_secondary(e.secondary_id);break;case"sync_secondaries":o=await w().sync_secondaries();break;case"get_secondary_health":o=w().get_secondary_health();break;case"get_forwarder_status":o=J().get_forwarder_status();break;default:o={...V(),connections:r?.get_stats()||{},write_queue:$()?.get_stats()||{},authentication:{authenticated_clients:s?.size||0,...q()},settings:(()=>{try{return{port:x().port||1983}}catch{return{port:1983}}})()}}const c=Date.now()-a;return Y(c),n.info("Admin operation completed",{admin_action:t||"default",duration_ms:c,status:"success"}),o}catch(o){const c=Date.now()-a;throw n.error("Admin operation failed",{admin_action:t||"default",duration_ms:c,status:"error",error:o.message}),o}};export{qe as default,Y as track_operation};
1
+ import{get_database as y}from"../query_engine.js";import{get_settings as $}from"../load_settings.js";import{get_write_queue as v}from"../write_queue.js";import{get_auth_stats as q}from"../auth_manager.js";import{get_query_statistics as E,get_auto_index_statistics as D,force_index_evaluation as O,remove_automatic_indexes as P}from"../auto_index_manager.js";import{create_index as N,drop_index as R,get_indexes as j}from"../index_manager.js";import{test_s3_connection as U,create_backup as W,list_backups as A,restore_backup as J,cleanup_old_backups as T}from"../backup_manager.js";import{get_replication_manager as b}from"../replication_manager.js";import{get_write_forwarder as B}from"../write_forwarder.js";import L from"../logger.js";import{performance_monitor as w}from"../performance_monitor.js";const{create_context_logger:h}=L("admin"),I=()=>{try{return $()}catch{return{port:1983}}},G=t=>{try{const e=t.getStats?t.getStats():{};return{pageSize:e.pageSize||0,treeDepth:e.treeDepth||0,treeBranchPages:e.treeBranchPages||0,treeLeafPages:e.treeLeafPages||0,entryCount:e.entryCount||0,mapSize:e.mapSize||0,lastPageNumber:e.lastPageNumber||0}}catch{return{error:"Could not retrieve database stats"}}},H=(t,e)=>{const o={};let r=0;try{for(const{key:n}of t.getRange())if(typeof n=="string"&&n.includes(":")&&!n.startsWith("_")){const a=n.split(":")[0];o[a]=(o[a]||0)+1,r++}}catch(n){e.warn("Could not iterate database range for stats",{error:n.message})}return{collections:o,total_documents:r}},z=()=>{const t=process.memoryUsage();return{rss:Math.round(t.rss/1024/1024),heapTotal:Math.round(t.heapTotal/1024/1024),heapUsed:Math.round(t.heapUsed/1024/1024),external:Math.round(t.external/1024/1024)}},K=t=>t.mapSize>0?Math.round(t.lastPageNumber*t.pageSize/t.mapSize*100):0,Q=t=>({uptime:Math.floor(process.uptime()),uptime_formatted:M(process.uptime()),memory_usage:t,memory_usage_raw:process.memoryUsage(),node_version:process.version,platform:process.platform,arch:process.arch,pid:process.pid,cpu_usage:process.cpuUsage()}),V=(t,e,o,r)=>({total_documents:t,total_collections:Object.keys(e).length,collections:e,stats:o,map_size_usage_percent:r,disk_usage:{map_size_mb:Math.round((o.mapSize||0)/1024/1024),used_space_mb:Math.round((o.lastPageNumber||0)*(o.pageSize||0)/1024/1024)}}),X=()=>{const t=h();try{const e=y(),o=I(),r=G(e),{collections:n,total_documents:a}=H(e,t),s=z(),i=K(r);return{server:Q(s),database:V(a,n,r,i),performance:{ops_per_second:F(),avg_response_time_ms:C()}}}catch(e){throw t.error("Failed to get enhanced stats",{error:e.message}),e}},M=t=>{const e=Math.floor(t/86400),o=Math.floor(t%86400/3600),r=Math.floor(t%3600/60),n=Math.floor(t%60);return e>0?`${e}d ${o}h ${r}m ${n}s`:o>0?`${o}h ${r}m ${n}s`:r>0?`${r}m ${n}s`:`${n}s`};let k=0,S=0,Y=Date.now();const F=()=>{const t=(Date.now()-Y)/1e3;return t>0?Math.round(k/t):0},C=()=>k>0?Math.round(S/k):0,Z=t=>{k++,S+=t},ee=t=>({name:t,document_count:0,indexes:[],estimated_size_bytes:0}),te=(t,e,o)=>{const r={};let n=0;try{for(const{key:a}of t.getRange())if(typeof a=="string"&&a.includes(":")&&!a.startsWith("_")){const s=a.split(":");if(s.length>=3){const i=s[0],c=s[1];i===e&&(r[c]||(r[c]=ee(c)),r[c].document_count++,n++)}}}catch(a){o.warn("Could not iterate database range for collections",{error:a.message})}return{collections_map:r,total_documents:n}},re=(t,e,o)=>{const r=["admin_test","test_collection","queue_test","users","products","orders","sessions","logs","analytics","settings","another_collection","list_test","pagination_test","get_test","query_test","admin_insert_test","admin_update_test","admin_delete_test"];let n=0;for(const a of r)try{const s=`${e}:${a}:`,i=t.getRange({start:s,end:s+"\xFF"});let c=0;for(const _ of i)c++,n++;c>0&&(o[a]={name:a,document_count:c,indexes:[],estimated_size_bytes:c*100})}catch{continue}return n},oe=(t,e,o,r)=>{try{const n=`index:${e}:`,a=t.getRange({start:n,end:n+"\xFF"});for(const{key:s,value:i}of a)if(typeof s=="string"&&s.startsWith(n)){const c=s.substring(n.length),_=c.split(":")[0],u=c.split(":")[1];o[_]&&u&&(o[_].indexes.includes(u)||o[_].indexes.push(u))}}catch(n){r.warn("Could not iterate index range",{error:n.message})}},se=(t="default")=>{const e=h();try{const o=y();let{collections_map:r,total_documents:n}=te(o,t,e);Object.keys(r).length===0&&(n+=re(o,t,r)),oe(o,t,r,e);const a=Object.values(r);return{collections:a,total_collections:a.length,total_documents:n}}catch(o){throw e.error("Failed to list collections",{error:o.message}),o}},ne=(t,e={})=>{const o=h();if(!t)throw new Error("Collection name is required");try{const r=y(),{limit:n=50,skip:a=0,sort_field:s,sort_order:i="asc",database:c="default"}=e,_=[],u=`${c}:${t}:`;let m=0,g=0;for(const{key:d,value:f}of r.getRange({start:u,end:u+"\xFF"}))if(typeof d=="string"&&d.startsWith(u)){if(g<a){g++;continue}if(m>=n)break;try{const l=JSON.parse(f),p=d.substring(u.length);_.push({_id:p,...l}),m++}catch(l){o.warn("Could not parse document",{collection:t,key:d,error:l.message})}}return s&&_.length>0&&_.sort((d,f)=>{const l=d[s],p=f[s];return i==="desc"?p>l?1:p<l?-1:0:l>p?1:l<p?-1:0}),{collection:t,documents:_,count:_.length,skip:a,limit:n,has_more:m===n}}catch(r){throw o.error("Failed to list documents",{collection:t,error:r.message}),r}},ae=(t,e,o="default")=>{const r=h();if(!t||!e)throw new Error("Collection name and document ID are required");try{const n=y(),a=`${o}:${t}:${e}`,s=n.get(a);if(!s)return{found:!1,collection:t,document_id:e};const i=JSON.parse(s);return{found:!0,collection:t,document_id:e,document:{_id:e,...i}}}catch(n){throw r.error("Failed to get document",{collection:t,document_id:e,error:n.message}),n}},ce=(t,e,o,r)=>{switch(t){case"$gt":return o>e;case"$gte":return o>=e;case"$lt":return o<e;case"$lte":return o<=e;case"$ne":return o!==e;case"$in":return Array.isArray(e)&&e.includes(o);case"$regex":const n=r.$options||"";return new RegExp(e,n).test(String(o));default:return o===r}},ie=(t,e)=>Object.keys(e).every(o=>{const r=e[o],n=t[o];return typeof r=="object"&&r!==null?Object.keys(r).every(a=>{const s=r[a];return ce(a,s,n,r)}):n===r}),_e=(t,e,o,r,n)=>{try{const a=JSON.parse(e),i={_id:t.substring(o.length),...a};return ie(i,r)?i:null}catch(a){return n.warn("Could not parse document during query",{key:t,error:a.message}),null}},ue=(t,e={},o={})=>{const r=h();if(!t)throw new Error("Collection name is required");try{const n=y(),{limit:a=100,skip:s=0,database:i="default"}=o,c=[],_=`${i}:${t}:`;let u=0,m=0,g=0;for(const{key:d,value:f}of n.getRange({start:_,end:_+"\xFF"}))if(typeof d=="string"&&d.startsWith(_)){g++;const l=_e(d,f,_,e,r);if(l){if(m<s){m++;continue}if(u>=a)break;c.push(l),u++}}return{collection:t,filter:e,documents:c,count:c.length,total_examined:g,skip:s,limit:a,has_more:u===a}}catch(n){throw r.error("Failed to query documents",{collection:t,filter:e,error:n.message}),n}},le=async(t,e,o,r={})=>await(await import("./insert_one.js")).default(t,e,o,r),de=async(t,e,o,r,n={})=>await(await import("./update_one.js")).default(t,e,o,r,n),me=async(t,e,o,r={})=>await(await import("./delete_one.js")).default(t,e,o,r);var qe=async(t,e={},o,r)=>{const n=h(),a=Date.now();try{let s;switch(t){case"stats":const c=z();s={server:{uptime:Math.floor(process.uptime()),uptime_formatted:M(process.uptime()),node_version:process.version,platform:process.platform,arch:process.arch,pid:process.pid},memory:{heap_used_mb:c.heapUsed,heap_total_mb:c.heapTotal,rss:c.rss,external:c.external},database:{...w.get_database_stats(),map_size_mb:Math.round((w.get_database_stats()?.map_size||0)/1024/1024),used_space_mb:Math.round((w.get_database_stats()?.used_space||0)/1024/1024),usage_percent:w.get_database_stats()?.usage_percent||0},performance:{ops_per_second:F(),avg_response_time_ms:C()},system:w.get_system_stats(),connections:o?.get_stats()||{active:r?.size||0,total:r?.size||0},write_queue:v()?.get_stats()||{},authentication:{authenticated_clients:r?.size||0,...q()},settings:(()=>{try{return{port:$().port||1983}}catch{return{port:1983}}})()};break;case"list_collections":s=se();break;case"list_documents":s=ne(e.collection,{limit:e.limit,skip:e.skip,sort_field:e.sort_field,sort_order:e.sort_order});break;case"get_document":s=ae(e.collection,e.document_id);break;case"query_documents":s=ue(e.collection,e.filter,{limit:e.limit,skip:e.skip});break;case"insert_document":s=await le(e.database||"default",e.collection,e.document,e.options);break;case"update_document":const _=e.document_id?{_id:e.document_id}:e.filter;s=await de(e.database||"default",e.collection,_,e.update,e.options);break;case"delete_document":const u=e.document_id?{_id:e.document_id}:e.filter;s=await me(e.database||"default",e.collection,u,e.options);break;case"test_s3_connection":s=await U();break;case"backup_now":s=await W();break;case"list_backups":s=await A();break;case"restore_backup":if(!e.backup_filename)throw new Error("backup_filename is required for restore operation");s=await J(e.backup_filename);break;case"cleanup_backups":s=await T();break;case"get_auto_index_stats":s=D();break;case"get_query_stats":s=E(e.collection);break;case"evaluate_auto_indexes":s=await O(e.collection);break;case"remove_auto_indexes":if(!e.collection)throw new Error("collection is required for remove_auto_indexes operation");s=await P(e.collection,e.field_names);break;case"create_index":if(!e.collection||!e.field)throw new Error("collection and field are required for create_index operation");s=await N(e.database||"default",e.collection,e.field,e.options);break;case"drop_index":if(!e.collection||!e.field)throw new Error("collection and field are required for drop_index operation");s=await R(e.database||"default",e.collection,e.field);break;case"get_indexes":if(!e.collection)throw new Error("collection is required for get_indexes operation");s={indexes:j(e.database||"default",e.collection)};break;case"get_replication_status":s=b().get_replication_status();break;case"add_secondary":if(!e.id||!e.ip||!e.port||!e.private_key)throw new Error("id, ip, port, and private_key are required for add_secondary operation");s=await b().add_secondary({id:e.id,ip:e.ip,port:e.port,private_key:e.private_key,enabled:!0});break;case"remove_secondary":if(!e.secondary_id)throw new Error("secondary_id is required for remove_secondary operation");s=b().remove_secondary(e.secondary_id);break;case"sync_secondaries":s=await b().sync_secondaries();break;case"get_secondary_health":s=b().get_secondary_health();break;case"get_forwarder_status":s=B().get_forwarder_status();break;default:s={...X(),connections:o?.get_stats()||{},write_queue:v()?.get_stats()||{},authentication:{authenticated_clients:r?.size||0,...q()},settings:(()=>{try{return{port:$().port||1983}}catch{return{port:1983}}})()}}const i=Date.now()-a;return Z(i),n.info("Admin operation completed",{admin_action:t||"default",duration_ms:i,status:"success"}),s}catch(s){const i=Date.now()-a;throw n.error("Admin operation failed",{admin_action:t||"default",duration_ms:i,status:"error",error:s.message}),s}};export{qe as default,Z as track_operation};
@@ -1 +1 @@
1
- import{get_database as O,build_collection_key as v,generate_document_id as j}from"../query_engine.js";import{update_indexes_on_update as x,update_indexes_on_insert as $}from"../index_manager.js";import{get_write_queue as S}from"../write_queue.js";import q from"../logger.js";const{create_context_logger:E}=q("update_one"),J=(e,r)=>({...e,...r}),N=(e,r)=>{const t={...e};for(const o of Object.keys(r))delete t[o];return t},A=(e,r)=>{const t={...e};for(const[o,n]of Object.entries(r))t[o]=(t[o]||0)+n;return t},F=(e,r)=>{const t={...e};for(const[o,n]of Object.entries(r))Array.isArray(t[o])||(t[o]=[]),t[o]=[...t[o],n];return t},U=(e,r)=>{const t={...e};for(const[o,n]of Object.entries(r))Array.isArray(t[o])&&(t[o]=t[o].filter(a=>a!==n));return t},w=(e,r)=>{let t={...e};for(const[o,n]of Object.entries(r))switch(o){case"$set":t=J(t,n);break;case"$unset":t=N(t,n);break;case"$inc":t=A(t,n);break;case"$push":t=F(t,n);break;case"$pull":t=U(t,n);break;default:throw new Error(`Unsupported update operator: ${o}`)}return t},D=(e,r,t)=>e[r]===t,C=(e,r)=>{if(!r||Object.keys(r).length===0)return!0;for(const[t,o]of Object.entries(r))if(!D(e,t,o))return!1;return!0},I=e=>{if(!e)throw new Error("Database name is required")},R=e=>{if(!e)throw new Error("Collection name is required")},z=e=>{if(!e||typeof e!="object")throw new Error("Filter must be a valid object")},B=e=>{if(!e||typeof e!="object")throw new Error("Update must be a valid object")},G=(e,r,t,o)=>{I(e),R(r),z(t),B(o)},H=e=>{try{return JSON.parse(e)}catch{return null}},b=()=>new Date().toISOString(),K=e=>({...e,_updated_at:b()}),L=(e,r)=>JSON.stringify(e)!==JSON.stringify(r),M=(e,r)=>{const t=j(),o=b(),n={...e,_id:t,_created_at:o,_updated_at:o};return w(n,r)},P=(e,r,t,o,n,a)=>{let c=0,u=0,d=null,i=null,_=null,s=null;const l=`${r}:${t}:`;let f=!1;const g=e.getRange({start:l,end:l+"\xFF"});for(const{key:m,value:h}of g){const p=H(h);if(p&&C(p,o)){f=!0,c=1;const k=w(p,n),y=K(k);L(p,y)&&(e.put(m,JSON.stringify(y)),i=p,_=y,u=1);break}}if(!f&&a.upsert){s=M(o,n);const m=v(r,t,s._id);e.put(m,JSON.stringify(s)),d=s._id,c=0,u=0}return{matched_count:c,modified_count:u,upserted_id:d,old_document:i,new_document:_,upserted_document:s}},Q=async(e,r,t,o)=>{t&&o&&await x(e,r,t,o)},T=async(e,r,t)=>{t&&await $(e,r,t)},V=(e,r,t,o,n,a)=>{e.info("Update operation completed",{database:r,collection:t,matched_count:o,modified_count:n,upserted_id:a})},W=(e,r,t)=>{const o={acknowledged:!0,matched_count:e,modified_count:r};return t&&(o.upserted_id=t),o},X=(e,r,t)=>({operation:"update_one",database:e,collection:r,filter_keys:Object.keys(t||{})}),Y=async(e,r,t,o,n={})=>{const a=E();G(e,r,t,o);const c=O(),u=await c.transaction(()=>P(c,e,r,t,o,n)),{matched_count:d,modified_count:i,upserted_id:_,old_document:s,new_document:l,upserted_document:f}=u;return await Q(e,r,s,l),await T(e,r,f),V(a,e,r,d,i,_),W(d,i,_)},Z=async(e,r,t,o,n={})=>{const a=S(),c=X(e,r,t);return await a.enqueue_write_operation(()=>Y(e,r,t,o,n),c)};var nt=Z;export{nt as default};
1
+ import{get_database as v,build_collection_key as O,generate_document_id as x}from"../query_engine.js";import{update_indexes_on_update as $,update_indexes_on_insert as S}from"../index_manager.js";import{get_write_queue as q}from"../write_queue.js";import E from"../logger.js";const{create_context_logger:J}=E("update_one"),w=(t,n,e)=>{const r=n.split("."),o={...t};let s=o;for(let c=0;c<r.length-1;c++){const u=r[c];!(u in s)||typeof s[u]!="object"||s[u]===null?s[u]={}:s[u]={...s[u]},s=s[u]}return s[r[r.length-1]]=e,o},N=(t,n)=>{let e={...t};for(const[r,o]of Object.entries(n))r.includes(".")?e=w(e,r,o):e[r]=o;return e},A=(t,n)=>{const e=n.split(".");let r=t;for(const o of e){if(r==null||typeof r!="object")return;r=r[o]}return r},F=(t,n)=>{const e=n.split("."),r={...t};let o=r;for(let s=0;s<e.length-1;s++){const c=e[s];if(!(c in o)||typeof o[c]!="object"||o[c]===null)return r;o[c]={...o[c]},o=o[c]}return delete o[e[e.length-1]],r},U=(t,n)=>{let e={...t};for(const r of Object.keys(n))r.includes(".")?e=F(e,r):delete e[r];return e},D=(t,n)=>{let e={...t};for(const[r,o]of Object.entries(n))if(r.includes(".")){const s=A(e,r)||0;e=w(e,r,s+o)}else e[r]=(e[r]||0)+o;return e},C=(t,n)=>{const e={...t};for(const[r,o]of Object.entries(n))Array.isArray(e[r])||(e[r]=[]),e[r]=[...e[r],o];return e},I=(t,n)=>{const e={...t};for(const[r,o]of Object.entries(n))Array.isArray(e[r])&&(e[r]=e[r].filter(s=>s!==o));return e},b=(t,n)=>{let e={...t};for(const[r,o]of Object.entries(n))switch(r){case"$set":e=N(e,o);break;case"$unset":e=U(e,o);break;case"$inc":e=D(e,o);break;case"$push":e=C(e,o);break;case"$pull":e=I(e,o);break;default:throw new Error(`Unsupported update operator: ${r}`)}return e},R=(t,n,e)=>t[n]===e,z=(t,n)=>{if(!n||Object.keys(n).length===0)return!0;for(const[e,r]of Object.entries(n))if(!R(t,e,r))return!1;return!0},B=t=>{if(!t)throw new Error("Database name is required")},G=t=>{if(!t)throw new Error("Collection name is required")},H=t=>{if(!t||typeof t!="object")throw new Error("Filter must be a valid object")},K=t=>{if(!t||typeof t!="object")throw new Error("Update must be a valid object")},L=(t,n,e,r)=>{B(t),G(n),H(e),K(r)},M=t=>{try{return JSON.parse(t)}catch{return null}},g=()=>new Date().toISOString(),P=t=>({...t,_updated_at:g()}),Q=(t,n)=>JSON.stringify(t)!==JSON.stringify(n),T=(t,n)=>{const e=x(),r=g(),o={...t,_id:e,_created_at:r,_updated_at:r};return b(o,n)},V=(t,n,e,r,o,s)=>{let c=0,u=0,i=null,d=null,l=null,a=null;const p=`${n}:${e}:`;let f=!1;const k=t.getRange({start:p,end:p+"\xFF"});for(const{key:m,value:h}of k){const _=M(h);if(_&&z(_,r)){f=!0,c=1;const j=b(_,o),y=P(j);Q(_,y)&&(t.put(m,JSON.stringify(y)),d=_,l=y,u=1);break}}if(!f&&s.upsert){a=T(r,o);const m=O(n,e,a._id);t.put(m,JSON.stringify(a)),i=a._id,c=0,u=0}return{matched_count:c,modified_count:u,upserted_id:i,old_document:d,new_document:l,upserted_document:a}},W=async(t,n,e,r)=>{e&&r&&await $(t,n,e,r)},X=async(t,n,e)=>{e&&await S(t,n,e)},Y=(t,n,e,r,o,s)=>{t.info("Update operation completed",{database:n,collection:e,matched_count:r,modified_count:o,upserted_id:s})},Z=(t,n,e)=>{const r={acknowledged:!0,matched_count:t,modified_count:n};return e&&(r.upserted_id=e),r},ee=(t,n,e)=>({operation:"update_one",database:t,collection:n,filter_keys:Object.keys(e||{})}),te=async(t,n,e,r,o={})=>{const s=J();L(t,n,e,r);const c=v(),u=await c.transaction(()=>V(c,t,n,e,r,o)),{matched_count:i,modified_count:d,upserted_id:l,old_document:a,new_document:p,upserted_document:f}=u;return await W(t,n,a,p),await X(t,n,f),Y(s,t,n,i,d,l),Z(i,d,l)},re=async(t,n,e,r,o={})=>{const s=q(),c=ee(t,n,e);return await s.enqueue_write_operation(()=>te(t,n,e,r,o),c)};var ue=re;export{ue as default};
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@joystick.js/db-canary",
3
3
  "type": "module",
4
- "version": "0.0.0-canary.2256",
5
- "canary_version": "0.0.0-canary.2255",
4
+ "version": "0.0.0-canary.2258",
5
+ "canary_version": "0.0.0-canary.2257",
6
6
  "description": "JoystickDB - A minimalist database server for the Joystick framework",
7
7
  "main": "./dist/server/index.js",
8
8
  "scripts": {
@@ -716,6 +716,7 @@ export default async (admin_action, data = {}, connection_manager, authenticated
716
716
 
717
717
  switch (admin_action) {
718
718
  case 'stats':
719
+ const memory_usage = calculate_memory_usage();
719
720
  result = {
720
721
  server: {
721
722
  uptime: Math.floor(process.uptime()),
@@ -725,7 +726,12 @@ export default async (admin_action, data = {}, connection_manager, authenticated
725
726
  arch: process.arch,
726
727
  pid: process.pid
727
728
  },
728
- memory: performance_monitor.get_memory_stats(),
729
+ memory: {
730
+ heap_used_mb: memory_usage.heapUsed,
731
+ heap_total_mb: memory_usage.heapTotal,
732
+ rss: memory_usage.rss,
733
+ external: memory_usage.external
734
+ },
729
735
  database: {
730
736
  ...performance_monitor.get_database_stats(),
731
737
  map_size_mb: Math.round((performance_monitor.get_database_stats()?.map_size || 0) / 1024 / 1024),
@@ -737,7 +743,10 @@ export default async (admin_action, data = {}, connection_manager, authenticated
737
743
  avg_response_time_ms: calculate_avg_response_time()
738
744
  },
739
745
  system: performance_monitor.get_system_stats(),
740
- connections: connection_manager?.get_stats() || {},
746
+ connections: connection_manager?.get_stats() || {
747
+ active: authenticated_clients?.size || 0,
748
+ total: authenticated_clients?.size || 0
749
+ },
741
750
  write_queue: get_write_queue()?.get_stats() || {},
742
751
  authentication: {
743
752
  authenticated_clients: authenticated_clients?.size || 0,
@@ -5,6 +5,32 @@ import create_logger from '../logger.js';
5
5
 
6
6
  const { create_context_logger } = create_logger('update_one');
7
7
 
8
+ /**
9
+ * Sets a nested field value using dot notation.
10
+ * @param {Object} obj - Object to update
11
+ * @param {string} path - Dot notation path (e.g., 'user.profile.name')
12
+ * @param {any} value - Value to set
13
+ * @returns {Object} Updated object
14
+ */
15
+ const set_nested_field = (obj, path, value) => {
16
+ const keys = path.split('.');
17
+ const result = { ...obj };
18
+ let current = result;
19
+
20
+ for (let i = 0; i < keys.length - 1; i++) {
21
+ const key = keys[i];
22
+ if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
23
+ current[key] = {};
24
+ } else {
25
+ current[key] = { ...current[key] };
26
+ }
27
+ current = current[key];
28
+ }
29
+
30
+ current[keys[keys.length - 1]] = value;
31
+ return result;
32
+ };
33
+
8
34
  /**
9
35
  * Applies $set operator to document.
10
36
  * @param {Object} document - Document to update
@@ -12,7 +38,63 @@ const { create_context_logger } = create_logger('update_one');
12
38
  * @returns {Object} Updated document
13
39
  */
14
40
  const apply_set_operator = (document, operations) => {
15
- return { ...document, ...operations };
41
+ let updated_document = { ...document };
42
+
43
+ for (const [field, value] of Object.entries(operations)) {
44
+ if (field.includes('.')) {
45
+ // Handle nested field updates with dot notation
46
+ updated_document = set_nested_field(updated_document, field, value);
47
+ } else {
48
+ // Handle simple field updates
49
+ updated_document[field] = value;
50
+ }
51
+ }
52
+
53
+ return updated_document;
54
+ };
55
+
56
+ /**
57
+ * Gets a nested field value using dot notation.
58
+ * @param {Object} obj - Object to get value from
59
+ * @param {string} path - Dot notation path (e.g., 'user.profile.name')
60
+ * @returns {any} Field value or undefined
61
+ */
62
+ const get_nested_field = (obj, path) => {
63
+ const keys = path.split('.');
64
+ let current = obj;
65
+
66
+ for (const key of keys) {
67
+ if (current === null || current === undefined || typeof current !== 'object') {
68
+ return undefined;
69
+ }
70
+ current = current[key];
71
+ }
72
+
73
+ return current;
74
+ };
75
+
76
+ /**
77
+ * Unsets a nested field using dot notation.
78
+ * @param {Object} obj - Object to update
79
+ * @param {string} path - Dot notation path (e.g., 'user.profile.name')
80
+ * @returns {Object} Updated object
81
+ */
82
+ const unset_nested_field = (obj, path) => {
83
+ const keys = path.split('.');
84
+ const result = { ...obj };
85
+ let current = result;
86
+
87
+ for (let i = 0; i < keys.length - 1; i++) {
88
+ const key = keys[i];
89
+ if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
90
+ return result; // Path doesn't exist, nothing to unset
91
+ }
92
+ current[key] = { ...current[key] };
93
+ current = current[key];
94
+ }
95
+
96
+ delete current[keys[keys.length - 1]];
97
+ return result;
16
98
  };
17
99
 
18
100
  /**
@@ -22,10 +104,18 @@ const apply_set_operator = (document, operations) => {
22
104
  * @returns {Object} Updated document
23
105
  */
24
106
  const apply_unset_operator = (document, operations) => {
25
- const updated_document = { ...document };
107
+ let updated_document = { ...document };
108
+
26
109
  for (const field of Object.keys(operations)) {
27
- delete updated_document[field];
110
+ if (field.includes('.')) {
111
+ // Handle nested field unset with dot notation
112
+ updated_document = unset_nested_field(updated_document, field);
113
+ } else {
114
+ // Handle simple field unset
115
+ delete updated_document[field];
116
+ }
28
117
  }
118
+
29
119
  return updated_document;
30
120
  };
31
121
 
@@ -36,10 +126,19 @@ const apply_unset_operator = (document, operations) => {
36
126
  * @returns {Object} Updated document
37
127
  */
38
128
  const apply_inc_operator = (document, operations) => {
39
- const updated_document = { ...document };
129
+ let updated_document = { ...document };
130
+
40
131
  for (const [field, value] of Object.entries(operations)) {
41
- updated_document[field] = (updated_document[field] || 0) + value;
132
+ if (field.includes('.')) {
133
+ // Handle nested field increment with dot notation
134
+ const current_value = get_nested_field(updated_document, field) || 0;
135
+ updated_document = set_nested_field(updated_document, field, current_value + value);
136
+ } else {
137
+ // Handle simple field increment
138
+ updated_document[field] = (updated_document[field] || 0) + value;
139
+ }
42
140
  }
141
+
43
142
  return updated_document;
44
143
  };
45
144