@joystick.js/db-canary 0.0.0-canary.2246 → 0.0.0-canary.2248

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,4 +1,4 @@
1
- import s from"./logger.js";const{create_context_logger:t}=s("development_mode"),n=t(),l=()=>process.env.NODE_ENV==="development",r=(e,o)=>{console.log(`
1
+ import s from"./logger.js";const{create_context_logger:t}=s("development_mode"),n=t(),l=()=>process.env.NODE_ENV==="development"||process.env.NODE_ENV==="test",r=(e,o)=>{console.log(`
2
2
  JoystickDB Development Mode
3
3
  `),console.log("Development environment detected (NODE_ENV=development)."),console.log(`Security features have been bypassed for local development.
4
4
  `),console.log("Default admin user created:"),console.log(" Username: admin"),console.log(` Password: password
@@ -1 +1 @@
1
- import{get_database as x}from"../query_engine.js";import{get_settings as q}from"../load_settings.js";import{get_write_queue as F}from"../write_queue.js";import{get_auth_stats as C}from"../auth_manager.js";import{get_query_statistics as O,get_auto_index_statistics as R,force_index_evaluation as j,remove_automatic_indexes as W}from"../auto_index_manager.js";import{create_index as A,drop_index as U,get_indexes as J}from"../index_manager.js";import{test_s3_connection as B,create_backup as L,list_backups as T,restore_backup as I,cleanup_old_backups as G}from"../backup_manager.js";import{get_replication_manager as v}from"../replication_manager.js";import{get_write_forwarder as H}from"../write_forwarder.js";import K from"../logger.js";import{performance_monitor as w}from"../performance_monitor.js";const{create_context_logger:k}=K("admin"),Q=()=>{const r=k();try{const e=x();let a;try{a=q()}catch{a={port:1983}}let o={};try{const s=e.getStats?e.getStats():{};o={pageSize:s.pageSize||0,treeDepth:s.treeDepth||0,treeBranchPages:s.treeBranchPages||0,treeLeafPages:s.treeLeafPages||0,entryCount:s.entryCount||0,mapSize:s.mapSize||0,lastPageNumber:s.lastPageNumber||0}}catch{o={error:"Could not retrieve database stats"}}const n={};let _=0;try{for(const{key:s}of e.getRange())if(typeof s=="string"&&s.includes(":")&&!s.startsWith("_")){const l=s.split(":")[0];n[l]=(n[l]||0)+1,_++}}catch(s){r.warn("Could not iterate database range for stats",{error:s.message})}const t=process.memoryUsage(),i={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)},c=o.mapSize>0?Math.round(o.lastPageNumber*o.pageSize/o.mapSize*100):0;return{server:{uptime:Math.floor(process.uptime()),uptime_formatted:E(process.uptime()),memory_usage:i,memory_usage_raw:t,node_version:process.version,platform:process.platform,arch:process.arch,pid:process.pid,cpu_usage:process.cpuUsage()},database:{total_documents:_,total_collections:Object.keys(n).length,collections:n,stats:o,map_size_usage_percent:c,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)}},performance:{ops_per_second:P(),avg_response_time_ms:N()}}}catch(e){throw r.error("Failed to get enhanced stats",{error:e.message}),e}},E=r=>{const e=Math.floor(r/86400),a=Math.floor(r%86400/3600),o=Math.floor(r%3600/60),n=Math.floor(r%60);return e>0?`${e}d ${a}h ${o}m ${n}s`:a>0?`${a}h ${o}m ${n}s`:o>0?`${o}m ${n}s`:`${n}s`};let $=0,D=0,V=Date.now();const P=()=>{const r=(Date.now()-V)/1e3;return r>0?Math.round($/r):0},N=()=>$>0?Math.round(D/$):0,X=r=>{$++,D+=r},Y=(r="default")=>{const e=k();try{const a=x(),o={};let n=0;try{for(const{key:t}of a.getRange())if(typeof t=="string"&&t.includes(":")&&!t.startsWith("_")){const i=t.split(":");if(i.length>=3){const c=i[0],s=i[1];c===r&&(o[s]||(o[s]={name:s,document_count:0,indexes:[],estimated_size_bytes:0}),o[s].document_count++,n++)}}}catch(t){e.warn("Could not iterate database range for collections",{error:t.message});const i=["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"];for(const c of i)try{const s=`${r}:${c}:`,l=a.getRange({start:s,end:s+"\xFF"});let u=0;for(const h of l)u++,n++;u>0&&(o[c]={name:c,document_count:u,indexes:[],estimated_size_bytes:u*100})}catch{continue}}try{const t=`index:${r}:`,i=a.getRange({start:t,end:t+"\xFF"});for(const{key:c,value:s}of i)if(typeof c=="string"&&c.startsWith(t)){const l=c.substring(t.length),u=l.split(":")[0];o[u]&&(o[u].indexes.includes(l.split(":")[1])||o[u].indexes.push(l.split(":")[1]))}}catch(t){e.warn("Could not iterate index range",{error:t.message})}const _=Object.values(o);return{collections:_,total_collections:_.length,total_documents:n}}catch(a){throw e.error("Failed to list collections",{error:a.message}),a}},Z=(r,e={})=>{const a=k();if(!r)throw new Error("Collection name is required");try{const o=x(),{limit:n=50,skip:_=0,sort_field:t,sort_order:i="asc",database:c="default"}=e,s=[],l=`${c}:${r}:`;let u=0,h=0;for(const{key:p,value:y}of o.getRange({start:l,end:l+"\xFF"}))if(typeof p=="string"&&p.startsWith(l)){if(h<_){h++;continue}if(u>=n)break;try{const d=JSON.parse(y),m=p.substring(l.length);s.push({_id:m,...d}),u++}catch(d){a.warn("Could not parse document",{collection:r,key:p,error:d.message})}}return t&&s.length>0&&s.sort((p,y)=>{const d=p[t],m=y[t];return i==="desc"?m>d?1:m<d?-1:0:d>m?1:d<m?-1:0}),{collection:r,documents:s,count:s.length,skip:_,limit:n,has_more:u===n}}catch(o){throw a.error("Failed to list documents",{collection:r,error:o.message}),o}},ee=(r,e,a="default")=>{const o=k();if(!r||!e)throw new Error("Collection name and document ID are required");try{const n=x(),_=`${a}:${r}:${e}`,t=n.get(_);if(!t)return{found:!1,collection:r,document_id:e};const i=JSON.parse(t);return{found:!0,collection:r,document_id:e,document:{_id:e,...i}}}catch(n){throw o.error("Failed to get document",{collection:r,document_id:e,error:n.message}),n}},te=(r,e={},a={})=>{const o=k();if(!r)throw new Error("Collection name is required");try{const n=x(),{limit:_=100,skip:t=0,database:i="default"}=a,c=[],s=`${i}:${r}:`;let l=0,u=0,h=0;for(const{key:p,value:y}of n.getRange({start:s,end:s+"\xFF"}))if(typeof p=="string"&&p.startsWith(s)){h++;try{const d=JSON.parse(y),z={_id:p.substring(s.length),...d};if(Object.keys(e).every(M=>{const b=e[M],g=z[M];return typeof b=="object"&&b!==null?Object.keys(b).every(S=>{const f=b[S];switch(S){case"$gt":return g>f;case"$gte":return g>=f;case"$lt":return g<f;case"$lte":return g<=f;case"$ne":return g!==f;case"$in":return Array.isArray(f)&&f.includes(g);case"$regex":return new RegExp(f).test(String(g));default:return g===b}}):g===b})){if(u<t){u++;continue}if(l>=_)break;c.push(z),l++}}catch(d){o.warn("Could not parse document during query",{collection:r,key:p,error:d.message})}}return{collection:r,filter:e,documents:c,count:c.length,total_examined:h,skip:t,limit:_,has_more:l===_}}catch(n){throw o.error("Failed to query documents",{collection:r,filter:e,error:n.message}),n}},re=async(r,e,a,o={})=>await(await import("./insert_one.js")).default(r,e,a,o),oe=async(r,e,a,o,n={})=>await(await import("./update_one.js")).default(r,e,a,o,n),se=async(r,e,a,o={})=>await(await import("./delete_one.js")).default(r,e,a,o);var he=async(r,e={},a,o)=>{const n=k(),_=Date.now();try{let t;switch(r){case"stats":t={server:{uptime:Math.floor(process.uptime()),uptime_formatted:E(process.uptime()),node_version:process.version,platform:process.platform,arch:process.arch,pid:process.pid},memory:w.get_memory_stats(),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:P(),avg_response_time_ms:N()},system:w.get_system_stats(),connections:a?.get_stats()||{},write_queue:F()?.get_stats()||{},authentication:{authenticated_clients:o?.size||0,...C()},settings:(()=>{try{return{port:q().port||1983}}catch{return{port:1983}}})()};break;case"list_collections":t=Y();break;case"list_documents":t=Z(e.collection,{limit:e.limit,skip:e.skip,sort_field:e.sort_field,sort_order:e.sort_order});break;case"get_document":t=ee(e.collection,e.document_id);break;case"query_documents":t=te(e.collection,e.filter,{limit:e.limit,skip:e.skip});break;case"insert_document":t=await re(e.database||"default",e.collection,e.document,e.options);break;case"update_document":const c=e.document_id?{_id:e.document_id}:e.filter;t=await oe(e.database||"default",e.collection,c,e.update,e.options);break;case"delete_document":const s=e.document_id?{_id:e.document_id}:e.filter;t=await se(e.database||"default",e.collection,s,e.options);break;case"test_s3_connection":t=await B();break;case"backup_now":t=await L();break;case"list_backups":t=await T();break;case"restore_backup":if(!e.backup_filename)throw new Error("backup_filename is required for restore operation");t=await I(e.backup_filename);break;case"cleanup_backups":t=await G();break;case"get_auto_index_stats":t=R();break;case"get_query_stats":t=O(e.collection);break;case"evaluate_auto_indexes":t=await j(e.collection);break;case"remove_auto_indexes":if(!e.collection)throw new Error("collection is required for remove_auto_indexes operation");t=await W(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");t=await A(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");t=await U(e.database||"default",e.collection,e.field);break;case"get_indexes":if(!e.collection)throw new Error("collection is required for get_indexes operation");t={indexes:J(e.database||"default",e.collection)};break;case"get_replication_status":t=v().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");t=await v().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");t=v().remove_secondary(e.secondary_id);break;case"sync_secondaries":t=await v().sync_secondaries();break;case"get_secondary_health":t=v().get_secondary_health();break;case"get_forwarder_status":t=H().get_forwarder_status();break;default:t={...Q(),connections:a?.get_stats()||{},write_queue:F()?.get_stats()||{},authentication:{authenticated_clients:o?.size||0,...C()},settings:(()=>{try{return{port:q().port||1983}}catch{return{port:1983}}})()}}const i=Date.now()-_;return X(i),n.info("Admin operation completed",{admin_action:r||"default",duration_ms:i,status:"success"}),t}catch(t){const i=Date.now()-_;throw n.error("Admin operation failed",{admin_action:r||"default",duration_ms:i,status:"error",error:t.message}),t}};export{he as default,X as track_operation};
1
+ import{get_database as x}from"../query_engine.js";import{get_settings as q}from"../load_settings.js";import{get_write_queue as F}from"../write_queue.js";import{get_auth_stats as C}from"../auth_manager.js";import{get_query_statistics as R,get_auto_index_statistics as j,force_index_evaluation as W,remove_automatic_indexes as A}from"../auto_index_manager.js";import{create_index as U,drop_index as J,get_indexes as B}from"../index_manager.js";import{test_s3_connection as L,create_backup as T,list_backups as I,restore_backup as G,cleanup_old_backups as H}from"../backup_manager.js";import{get_replication_manager as v}from"../replication_manager.js";import{get_write_forwarder as K}from"../write_forwarder.js";import Q from"../logger.js";import{performance_monitor as w}from"../performance_monitor.js";const{create_context_logger:k}=Q("admin"),V=()=>{const r=k();try{const e=x();let a;try{a=q()}catch{a={port:1983}}let o={};try{const s=e.getStats?e.getStats():{};o={pageSize:s.pageSize||0,treeDepth:s.treeDepth||0,treeBranchPages:s.treeBranchPages||0,treeLeafPages:s.treeLeafPages||0,entryCount:s.entryCount||0,mapSize:s.mapSize||0,lastPageNumber:s.lastPageNumber||0}}catch{o={error:"Could not retrieve database stats"}}const n={};let _=0;try{for(const{key:s}of e.getRange())if(typeof s=="string"&&s.includes(":")&&!s.startsWith("_")){const l=s.split(":")[0];n[l]=(n[l]||0)+1,_++}}catch(s){r.warn("Could not iterate database range for stats",{error:s.message})}const t=process.memoryUsage(),i={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)},c=o.mapSize>0?Math.round(o.lastPageNumber*o.pageSize/o.mapSize*100):0;return{server:{uptime:Math.floor(process.uptime()),uptime_formatted:E(process.uptime()),memory_usage:i,memory_usage_raw:t,node_version:process.version,platform:process.platform,arch:process.arch,pid:process.pid,cpu_usage:process.cpuUsage()},database:{total_documents:_,total_collections:Object.keys(n).length,collections:n,stats:o,map_size_usage_percent:c,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)}},performance:{ops_per_second:P(),avg_response_time_ms:N()}}}catch(e){throw r.error("Failed to get enhanced stats",{error:e.message}),e}},E=r=>{const e=Math.floor(r/86400),a=Math.floor(r%86400/3600),o=Math.floor(r%3600/60),n=Math.floor(r%60);return e>0?`${e}d ${a}h ${o}m ${n}s`:a>0?`${a}h ${o}m ${n}s`:o>0?`${o}m ${n}s`:`${n}s`};let $=0,D=0,X=Date.now();const P=()=>{const r=(Date.now()-X)/1e3;return r>0?Math.round($/r):0},N=()=>$>0?Math.round(D/$):0,Y=r=>{$++,D+=r},Z=(r="default")=>{const e=k();try{const a=x(),o={};let n=0;try{for(const{key:t}of a.getRange())if(typeof t=="string"&&t.includes(":")&&!t.startsWith("_")){const i=t.split(":");if(i.length>=3){const c=i[0],s=i[1];c===r&&(o[s]||(o[s]={name:s,document_count:0,indexes:[],estimated_size_bytes:0}),o[s].document_count++,n++)}}}catch(t){e.warn("Could not iterate database range for collections",{error:t.message});const i=["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"];for(const c of i)try{const s=`${r}:${c}:`,l=a.getRange({start:s,end:s+"\xFF"});let u=0;for(const h of l)u++,n++;u>0&&(o[c]={name:c,document_count:u,indexes:[],estimated_size_bytes:u*100})}catch{continue}}try{const t=`index:${r}:`,i=a.getRange({start:t,end:t+"\xFF"});for(const{key:c,value:s}of i)if(typeof c=="string"&&c.startsWith(t)){const l=c.substring(t.length),u=l.split(":")[0];o[u]&&(o[u].indexes.includes(l.split(":")[1])||o[u].indexes.push(l.split(":")[1]))}}catch(t){e.warn("Could not iterate index range",{error:t.message})}const _=Object.values(o);return{collections:_,total_collections:_.length,total_documents:n}}catch(a){throw e.error("Failed to list collections",{error:a.message}),a}},ee=(r,e={})=>{const a=k();if(!r)throw new Error("Collection name is required");try{const o=x(),{limit:n=50,skip:_=0,sort_field:t,sort_order:i="asc",database:c="default"}=e,s=[],l=`${c}:${r}:`;let u=0,h=0;for(const{key:p,value:b}of o.getRange({start:l,end:l+"\xFF"}))if(typeof p=="string"&&p.startsWith(l)){if(h<_){h++;continue}if(u>=n)break;try{const d=JSON.parse(b),m=p.substring(l.length);s.push({_id:m,...d}),u++}catch(d){a.warn("Could not parse document",{collection:r,key:p,error:d.message})}}return t&&s.length>0&&s.sort((p,b)=>{const d=p[t],m=b[t];return i==="desc"?m>d?1:m<d?-1:0:d>m?1:d<m?-1:0}),{collection:r,documents:s,count:s.length,skip:_,limit:n,has_more:u===n}}catch(o){throw a.error("Failed to list documents",{collection:r,error:o.message}),o}},te=(r,e,a="default")=>{const o=k();if(!r||!e)throw new Error("Collection name and document ID are required");try{const n=x(),_=`${a}:${r}:${e}`,t=n.get(_);if(!t)return{found:!1,collection:r,document_id:e};const i=JSON.parse(t);return{found:!0,collection:r,document_id:e,document:{_id:e,...i}}}catch(n){throw o.error("Failed to get document",{collection:r,document_id:e,error:n.message}),n}},re=(r,e={},a={})=>{const o=k();if(!r)throw new Error("Collection name is required");try{const n=x(),{limit:_=100,skip:t=0,database:i="default"}=a,c=[],s=`${i}:${r}:`;let l=0,u=0,h=0;for(const{key:p,value:b}of n.getRange({start:s,end:s+"\xFF"}))if(typeof p=="string"&&p.startsWith(s)){h++;try{const d=JSON.parse(b),z={_id:p.substring(s.length),...d};if(Object.keys(e).every(M=>{const y=e[M],g=z[M];return typeof y=="object"&&y!==null?Object.keys(y).every(S=>{const f=y[S];switch(S){case"$gt":return g>f;case"$gte":return g>=f;case"$lt":return g<f;case"$lte":return g<=f;case"$ne":return g!==f;case"$in":return Array.isArray(f)&&f.includes(g);case"$regex":const O=y.$options||"";return new RegExp(f,O).test(String(g));default:return g===y}}):g===y})){if(u<t){u++;continue}if(l>=_)break;c.push(z),l++}}catch(d){o.warn("Could not parse document during query",{collection:r,key:p,error:d.message})}}return{collection:r,filter:e,documents:c,count:c.length,total_examined:h,skip:t,limit:_,has_more:l===_}}catch(n){throw o.error("Failed to query documents",{collection:r,filter:e,error:n.message}),n}},oe=async(r,e,a,o={})=>await(await import("./insert_one.js")).default(r,e,a,o),se=async(r,e,a,o,n={})=>await(await import("./update_one.js")).default(r,e,a,o,n),ne=async(r,e,a,o={})=>await(await import("./delete_one.js")).default(r,e,a,o);var ye=async(r,e={},a,o)=>{const n=k(),_=Date.now();try{let t;switch(r){case"stats":t={server:{uptime:Math.floor(process.uptime()),uptime_formatted:E(process.uptime()),node_version:process.version,platform:process.platform,arch:process.arch,pid:process.pid},memory:w.get_memory_stats(),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:P(),avg_response_time_ms:N()},system:w.get_system_stats(),connections:a?.get_stats()||{},write_queue:F()?.get_stats()||{},authentication:{authenticated_clients:o?.size||0,...C()},settings:(()=>{try{return{port:q().port||1983}}catch{return{port:1983}}})()};break;case"list_collections":t=Z();break;case"list_documents":t=ee(e.collection,{limit:e.limit,skip:e.skip,sort_field:e.sort_field,sort_order:e.sort_order});break;case"get_document":t=te(e.collection,e.document_id);break;case"query_documents":t=re(e.collection,e.filter,{limit:e.limit,skip:e.skip});break;case"insert_document":t=await oe(e.database||"default",e.collection,e.document,e.options);break;case"update_document":const c=e.document_id?{_id:e.document_id}:e.filter;t=await se(e.database||"default",e.collection,c,e.update,e.options);break;case"delete_document":const s=e.document_id?{_id:e.document_id}:e.filter;t=await ne(e.database||"default",e.collection,s,e.options);break;case"test_s3_connection":t=await L();break;case"backup_now":t=await T();break;case"list_backups":t=await I();break;case"restore_backup":if(!e.backup_filename)throw new Error("backup_filename is required for restore operation");t=await G(e.backup_filename);break;case"cleanup_backups":t=await H();break;case"get_auto_index_stats":t=j();break;case"get_query_stats":t=R(e.collection);break;case"evaluate_auto_indexes":t=await W(e.collection);break;case"remove_auto_indexes":if(!e.collection)throw new Error("collection is required for remove_auto_indexes operation");t=await A(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");t=await U(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");t=await J(e.database||"default",e.collection,e.field);break;case"get_indexes":if(!e.collection)throw new Error("collection is required for get_indexes operation");t={indexes:B(e.database||"default",e.collection)};break;case"get_replication_status":t=v().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");t=await v().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");t=v().remove_secondary(e.secondary_id);break;case"sync_secondaries":t=await v().sync_secondaries();break;case"get_secondary_health":t=v().get_secondary_health();break;case"get_forwarder_status":t=K().get_forwarder_status();break;default:t={...V(),connections:a?.get_stats()||{},write_queue:F()?.get_stats()||{},authentication:{authenticated_clients:o?.size||0,...C()},settings:(()=>{try{return{port:q().port||1983}}catch{return{port:1983}}})()}}const i=Date.now()-_;return Y(i),n.info("Admin operation completed",{admin_action:r||"default",duration_ms:i,status:"success"}),t}catch(t){const i=Date.now()-_;throw n.error("Admin operation failed",{admin_action:r||"default",duration_ms:i,status:"error",error:t.message}),t}};export{ye as default,Y as track_operation};
@@ -1 +1 @@
1
- import{get_database as D,build_collection_key as A}from"../query_engine.js";import{can_use_index as J,find_documents_by_index as v}from"../index_manager.js";import{record_query as N,record_index_usage as F}from"../auto_index_manager.js";import S from"../logger.js";const{create_context_logger:R}=S("find"),C=(n,r)=>{const s=r.split(".");let t=n;for(const e of s){if(t==null)return;t=t[e]}return t},P=(n,r)=>{const s=r.split(".");let t=n;for(let e=0;e<s.length;e++){if(t==null||typeof t!="object")return!1;if(e===s.length-1)return t.hasOwnProperty(s[e]);t=t[s[e]]}return!1},m=(n,r)=>{if(!r||Object.keys(r).length===0)return!0;for(const[s,t]of Object.entries(r)){const e=C(n,s);if(typeof t=="object"&&t!==null&&!Array.isArray(t))for(const[i,o]of Object.entries(t))switch(i){case"$eq":if(e!==o)return!1;break;case"$ne":if(e===o)return!1;break;case"$gt":if(e<=o)return!1;break;case"$gte":if(e<o)return!1;break;case"$lt":if(e>=o)return!1;break;case"$lte":if(e>o)return!1;break;case"$in":if(!Array.isArray(o)||!o.includes(e))return!1;break;case"$nin":if(!Array.isArray(o)||o.includes(e))return!1;break;case"$exists":const c=P(n,s);if(o&&!c||!o&&c)return!1;break;case"$regex":if(!new RegExp(o).test(e))return!1;break;default:throw new Error(`Unsupported query operator: ${i}`)}else if(e!==t)return!1}return!0},U=(n,r)=>{if(!r||Object.keys(r).length===0)return n;const s=Object.values(r).some(e=>e===1||e===!0),t={};if(s){t._id=n._id;for(const[e,i]of Object.entries(r))e==="_id"&&(i===0||i===!1)?delete t._id:(i===1||i===!0)&&(t[e]=n[e])}else{Object.assign(t,n);for(const[e,i]of Object.entries(r))(i===0||i===!1)&&delete t[e]}return t},z=(n,r)=>!r||Object.keys(r).length===0?n:n.sort((s,t)=>{for(const[e,i]of Object.entries(r)){const o=s[e],c=t[e];if(o===c)continue;if(o===void 0)return 1;if(c===void 0)return-1;const l=o<c?-1:o>c?1:0;return i===-1?-l:l}return 0}),B=async(n,r,s={},t={})=>{const e=R();if(!n)throw new Error("Database name is required");if(!r)throw new Error("Collection name is required");const i=D(),{projection:o,sort:c,limit:l,skip:O=0}=t,E=Date.now();try{let u=[],_=!1,h=null;const j=J(n,r,s);if(j){const{field:f,operators:b}=j,a=s[f];if(h=f,typeof a=="object"&&a!==null&&!Array.isArray(a)){for(const d of b)if(a[d]!==void 0){const p=v(n,r,f,d,a[d]);if(p){_=!0,F(n,r,f);for(const k of p){const x=A(n,r,k),y=i.get(x);if(y){const q=JSON.parse(y);m(q,s)&&u.push(q)}}break}}}else if(b.includes("eq")){const d=v(n,r,f,"eq",a);if(d){_=!0,F(n,r,f);for(const p of d){const k=A(n,r,p),x=i.get(k);if(x){const y=JSON.parse(x);m(y,s)&&u.push(y)}}}}}if(!_){const f=`${n}:${r}:`,b=i.getRange({start:f,end:f+"\xFF"});for(const{key:a,value:d}of b){const p=JSON.parse(d);m(p,s)&&u.push(p)}}let g=z(u,c);O>0&&(g=g.slice(O)),l&&l>0&&(g=g.slice(0,l));const w=g.map(f=>U(f,o)),$=Date.now()-E;try{N(r,s,$,_,h)}catch(f){e.warn("Failed to record query for auto-indexing",{error:f.message})}return e.info("Find operation completed",{database:n,collection:r,documents_found:w.length,total_matching:u.length,used_index:_,indexed_field:h,execution_time_ms:$}),w}catch(u){throw e.error("Failed to find documents",{database:n,collection:r,error:u.message}),u}};var L=B;export{L as default};
1
+ import{get_database as D,build_collection_key as A}from"../query_engine.js";import{can_use_index as J,find_documents_by_index as v}from"../index_manager.js";import{record_query as N,record_index_usage as F}from"../auto_index_manager.js";import S from"../logger.js";const{create_context_logger:R}=S("find"),C=(n,t)=>{const o=t.split(".");let r=n;for(const e of o){if(r==null)return;r=r[e]}return r},P=(n,t)=>{const o=t.split(".");let r=n;for(let e=0;e<o.length;e++){if(r==null||typeof r!="object")return!1;if(e===o.length-1)return r.hasOwnProperty(o[e]);r=r[o[e]]}return!1},O=(n,t)=>{if(!t||Object.keys(t).length===0)return!0;for(const[o,r]of Object.entries(t)){const e=C(n,o);if(typeof r=="object"&&r!==null&&!Array.isArray(r))for(const[i,s]of Object.entries(r))switch(i){case"$eq":if(e!==s)return!1;break;case"$ne":if(e===s)return!1;break;case"$gt":if(e<=s)return!1;break;case"$gte":if(e<s)return!1;break;case"$lt":if(e>=s)return!1;break;case"$lte":if(e>s)return!1;break;case"$in":if(!Array.isArray(s)||!s.includes(e))return!1;break;case"$nin":if(!Array.isArray(s)||s.includes(e))return!1;break;case"$exists":const c=P(n,o);if(s&&!c||!s&&c)return!1;break;case"$regex":const u=r.$options||"";if(!new RegExp(s,u).test(e))return!1;break;default:throw new Error(`Unsupported query operator: ${i}`)}else if(e!==r)return!1}return!0},U=(n,t)=>{if(!t||Object.keys(t).length===0)return n;const o=Object.values(t).some(e=>e===1||e===!0),r={};if(o){r._id=n._id;for(const[e,i]of Object.entries(t))e==="_id"&&(i===0||i===!1)?delete r._id:(i===1||i===!0)&&(r[e]=n[e])}else{Object.assign(r,n);for(const[e,i]of Object.entries(t))(i===0||i===!1)&&delete r[e]}return r},z=(n,t)=>!t||Object.keys(t).length===0?n:n.sort((o,r)=>{for(const[e,i]of Object.entries(t)){const s=o[e],c=r[e];if(s===c)continue;if(s===void 0)return 1;if(c===void 0)return-1;const u=s<c?-1:s>c?1:0;return i===-1?-u:u}return 0}),B=async(n,t,o={},r={})=>{const e=R();if(!n)throw new Error("Database name is required");if(!t)throw new Error("Collection name is required");const i=D(),{projection:s,sort:c,limit:u,skip:h=0}=r,E=Date.now();try{let d=[],_=!1,k=null;const $=J(n,t,o);if($){const{field:f,operators:x}=$,a=o[f];if(k=f,typeof a=="object"&&a!==null&&!Array.isArray(a)){for(const l of x)if(a[l]!==void 0){const p=v(n,t,f,l,a[l]);if(p){_=!0,F(n,t,f);for(const m of p){const b=A(n,t,m),y=i.get(b);if(y){const q=JSON.parse(y);O(q,o)&&d.push(q)}}break}}}else if(x.includes("eq")){const l=v(n,t,f,"eq",a);if(l){_=!0,F(n,t,f);for(const p of l){const m=A(n,t,p),b=i.get(m);if(b){const y=JSON.parse(b);O(y,o)&&d.push(y)}}}}}if(!_){const f=`${n}:${t}:`,x=i.getRange({start:f,end:f+"\xFF"});for(const{key:a,value:l}of x){const p=JSON.parse(l);O(p,o)&&d.push(p)}}let g=z(d,c);h>0&&(g=g.slice(h)),u&&u>0&&(g=g.slice(0,u));const j=g.map(f=>U(f,s)),w=Date.now()-E;try{N(t,o,w,_,k)}catch(f){e.warn("Failed to record query for auto-indexing",{error:f.message})}return e.info("Find operation completed",{database:n,collection:t,documents_found:j.length,total_matching:d.length,used_index:_,indexed_field:k,execution_time_ms:w}),j}catch(d){throw e.error("Failed to find documents",{database:n,collection:t,error:d.message}),d}};var L=B;export{L as default};
@@ -1 +1 @@
1
- import{get_database as A,build_collection_key as j}from"../query_engine.js";import{can_use_index as v,find_documents_by_index as m}from"../index_manager.js";import{record_query as D,record_index_usage as q}from"../auto_index_manager.js";import E from"../logger.js";const{create_context_logger:F}=E("find_one"),N=(o,r)=>{const n=r.split(".");let t=o;for(const e of n){if(t==null)return;t=t[e]}return t},J=(o,r)=>{const n=r.split(".");let t=o;for(let e=0;e<n.length;e++){if(t==null||typeof t!="object")return!1;if(e===n.length-1)return t.hasOwnProperty(n[e]);t=t[n[e]]}return!1},w=(o,r)=>{if(!r||Object.keys(r).length===0)return!0;for(const[n,t]of Object.entries(r)){const e=N(o,n);if(typeof t=="object"&&t!==null&&!Array.isArray(t))for(const[i,s]of Object.entries(t))switch(i){case"$eq":if(e!==s)return!1;break;case"$ne":if(e===s)return!1;break;case"$gt":if(e<=s)return!1;break;case"$gte":if(e<s)return!1;break;case"$lt":if(e>=s)return!1;break;case"$lte":if(e>s)return!1;break;case"$in":if(!Array.isArray(s)||!s.includes(e))return!1;break;case"$nin":if(!Array.isArray(s)||s.includes(e))return!1;break;case"$exists":const x=J(o,n);if(s&&!x||!s&&x)return!1;break;case"$regex":if(!new RegExp(s).test(e))return!1;break;default:throw new Error(`Unsupported query operator: ${i}`)}else if(e!==t)return!1}return!0},S=(o,r)=>{if(!r||Object.keys(r).length===0)return o;const n=Object.values(r).some(e=>e===1||e===!0),t={};if(n){t._id=o._id;for(const[e,i]of Object.entries(r))e==="_id"&&(i===0||i===!1)?delete t._id:(i===1||i===!0)&&(t[e]=o[e])}else{Object.assign(t,o);for(const[e,i]of Object.entries(r))(i===0||i===!1)&&delete t[e]}return t},R=async(o,r,n={},t={})=>{const e=F();if(!o)throw new Error("Database name is required");if(!r)throw new Error("Collection name is required");const i=A(),{projection:s,sort:x}=t,$=Date.now();try{let c=null,a=!1,_=null;const O=v(o,r,n);if(O){const{field:f,operators:g}=O,d=n[f];if(_=f,typeof d=="object"&&d!==null&&!Array.isArray(d)){for(const u of g)if(d[u]!==void 0){const l=m(o,r,f,u,d[u]);if(l&&l.length>0){a=!0,q(o,r,f);for(const k of l){const y=j(o,r,k),p=i.get(y);if(p)try{const h=JSON.parse(p);if(w(h,n)){c=h;break}}catch{continue}}break}}}else if(g.includes("eq")){const u=m(o,r,f,"eq",d);if(u&&u.length>0){a=!0,q(o,r,f);for(const l of u){const k=j(o,r,l),y=i.get(k);if(y)try{const p=JSON.parse(y);if(w(p,n)){c=p;break}}catch{continue}}}}}if(!a){const f=`${o}:${r}:`,g=i.getRange({start:f,end:f+"\xFF"});for(const{key:d,value:u}of g)try{const l=JSON.parse(u);if(w(l,n)){c=l;break}}catch{continue}}const b=Date.now()-$;try{D(r,n,b,a,_)}catch(f){e.warn("Failed to record query for auto-indexing",{error:f.message})}if(c){const f=S(c,s);return e.info("Document found",{database:o,collection:r,document_id:c._id,used_index:a,indexed_field:_,execution_time_ms:b}),f}return e.info("No document found",{database:o,collection:r,used_index:a,indexed_field:_,execution_time_ms:b}),null}catch(c){throw e.error("Failed to find document",{database:o,collection:r,error:c.message}),c}};var B=R;export{B as default};
1
+ import{get_database as A,build_collection_key as j}from"../query_engine.js";import{can_use_index as v,find_documents_by_index as m}from"../index_manager.js";import{record_query as D,record_index_usage as q}from"../auto_index_manager.js";import E from"../logger.js";const{create_context_logger:F}=E("find_one"),N=(o,t)=>{const n=t.split(".");let r=o;for(const e of n){if(r==null)return;r=r[e]}return r},J=(o,t)=>{const n=t.split(".");let r=o;for(let e=0;e<n.length;e++){if(r==null||typeof r!="object")return!1;if(e===n.length-1)return r.hasOwnProperty(n[e]);r=r[n[e]]}return!1},w=(o,t)=>{if(!t||Object.keys(t).length===0)return!0;for(const[n,r]of Object.entries(t)){const e=N(o,n);if(typeof r=="object"&&r!==null&&!Array.isArray(r))for(const[i,s]of Object.entries(r))switch(i){case"$eq":if(e!==s)return!1;break;case"$ne":if(e===s)return!1;break;case"$gt":if(e<=s)return!1;break;case"$gte":if(e<s)return!1;break;case"$lt":if(e>=s)return!1;break;case"$lte":if(e>s)return!1;break;case"$in":if(!Array.isArray(s)||!s.includes(e))return!1;break;case"$nin":if(!Array.isArray(s)||s.includes(e))return!1;break;case"$exists":const x=J(o,n);if(s&&!x||!s&&x)return!1;break;case"$regex":const b=r.$options||"";if(!new RegExp(s,b).test(e))return!1;break;default:throw new Error(`Unsupported query operator: ${i}`)}else if(e!==r)return!1}return!0},S=(o,t)=>{if(!t||Object.keys(t).length===0)return o;const n=Object.values(t).some(e=>e===1||e===!0),r={};if(n){r._id=o._id;for(const[e,i]of Object.entries(t))e==="_id"&&(i===0||i===!1)?delete r._id:(i===1||i===!0)&&(r[e]=o[e])}else{Object.assign(r,o);for(const[e,i]of Object.entries(t))(i===0||i===!1)&&delete r[e]}return r},R=async(o,t,n={},r={})=>{const e=F();if(!o)throw new Error("Database name is required");if(!t)throw new Error("Collection name is required");const i=A(),{projection:s,sort:x}=r,b=Date.now();try{let c=null,a=!1,_=null;const O=v(o,t,n);if(O){const{field:f,operators:g}=O,d=n[f];if(_=f,typeof d=="object"&&d!==null&&!Array.isArray(d)){for(const u of g)if(d[u]!==void 0){const l=m(o,t,f,u,d[u]);if(l&&l.length>0){a=!0,q(o,t,f);for(const h of l){const y=j(o,t,h),p=i.get(y);if(p)try{const $=JSON.parse(p);if(w($,n)){c=$;break}}catch{continue}}break}}}else if(g.includes("eq")){const u=m(o,t,f,"eq",d);if(u&&u.length>0){a=!0,q(o,t,f);for(const l of u){const h=j(o,t,l),y=i.get(h);if(y)try{const p=JSON.parse(y);if(w(p,n)){c=p;break}}catch{continue}}}}}if(!a){const f=`${o}:${t}:`,g=i.getRange({start:f,end:f+"\xFF"});for(const{key:d,value:u}of g)try{const l=JSON.parse(u);if(w(l,n)){c=l;break}}catch{continue}}const k=Date.now()-b;try{D(t,n,k,a,_)}catch(f){e.warn("Failed to record query for auto-indexing",{error:f.message})}if(c){const f=S(c,s);return e.info("Document found",{database:o,collection:t,document_id:c._id,used_index:a,indexed_field:_,execution_time_ms:k}),f}return e.info("No document found",{database:o,collection:t,used_index:a,indexed_field:_,execution_time_ms:k}),null}catch(c){throw e.error("Failed to find document",{database:o,collection:t,error:c.message}),c}};var B=R;export{B 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.2246",
5
- "canary_version": "0.0.0-canary.2245",
4
+ "version": "0.0.0-canary.2248",
5
+ "canary_version": "0.0.0-canary.2247",
6
6
  "description": "JoystickDB - A minimalist database server for the Joystick framework",
7
7
  "main": "./dist/server/index.js",
8
8
  "scripts": {
@@ -12,10 +12,10 @@ const log = create_context_logger();
12
12
 
13
13
  /**
14
14
  * Checks if the server is running in development mode.
15
- * @returns {boolean} True if NODE_ENV is set to 'development'
15
+ * @returns {boolean} True if NODE_ENV is set to 'development' or 'test'
16
16
  */
17
17
  const is_development_mode = () => {
18
- return process.env.NODE_ENV === 'development';
18
+ return process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
19
19
  };
20
20
 
21
21
  /**
@@ -469,7 +469,10 @@ const query_documents = (collection, filter = {}, options = {}) => {
469
469
  case '$lte': return doc_value <= op_value;
470
470
  case '$ne': return doc_value !== op_value;
471
471
  case '$in': return Array.isArray(op_value) && op_value.includes(doc_value);
472
- case '$regex': return new RegExp(op_value).test(String(doc_value));
472
+ case '$regex':
473
+ // Handle $options parameter for regex flags
474
+ const regex_options = filter_value.$options || '';
475
+ return new RegExp(op_value, regex_options).test(String(doc_value));
473
476
  default: return doc_value === filter_value;
474
477
  }
475
478
  });
@@ -105,7 +105,9 @@ const matches_filter = (document, filter) => {
105
105
  if (!operand && exists) return false;
106
106
  break;
107
107
  case '$regex':
108
- const regex = new RegExp(operand);
108
+ // Handle $options parameter for regex flags
109
+ const regex_options = value.$options || '';
110
+ const regex = new RegExp(operand, regex_options);
109
111
  if (!regex.test(field_value)) return false;
110
112
  break;
111
113
  default:
@@ -106,7 +106,9 @@ const matches_filter = (document, filter) => {
106
106
  if (!operand && exists) return false;
107
107
  break;
108
108
  case '$regex':
109
- const regex = new RegExp(operand);
109
+ // Handle $options parameter for regex flags
110
+ const regex_options = value.$options || '';
111
+ const regex = new RegExp(operand, regex_options);
110
112
  if (!regex.test(field_value)) return false;
111
113
  break;
112
114
  default: