@joystick.js/db-canary 0.0.0-canary.2229 → 0.0.0-canary.2231

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*as l from"lmdb";import{rmSync as d,existsSync as u}from"fs";import m from"./logger.js";import{calculate_map_size as p,get_disk_size as g,should_grow_map_size as f}from"./disk_utils.js";import{initialize_index_database as z,cleanup_index_database as b}from"./index_manager.js";import{initialize_auto_index_database as h,cleanup_auto_index_database as w}from"./auto_index_manager.js";const{create_context_logger:_}=m("query_engine");let a=null,r=null,o=null;const y=(t="./data")=>{const e=_();return a||(o=t,p(o).then(i=>{r=i,a&&a.resize&&(a.resize(r),e.info("Database map_size updated",{path:o,map_size:r,map_size_gb:Math.round(r/(1024*1024*1024)*100)/100}))}).catch(i=>{e.warn("Failed to calculate map_size, using default",{database_path:o,error:i.message})}),r=1024*1024*1024*10,a=l.open({path:o,compression:!0,useVersions:!1,encoding:"msgpack",mapSize:r}),e.info("Database initialized",{path:o,map_size:r,map_size_gb:Math.round(r/(1024*1024*1024)*100)/100}),z(),h()),a},k=async()=>{if(!a||!o)return;const t=_();try{const e=a.getStats?a.getStats():{},s=e.ms_psize*e.ms_leaf_pages||0;if(s===0)return;const i=await g(o),n=f(r,s,i);n&&(t.info("Growing map_size",{current_map_size:r,new_map_size:n,used_size:s,usage_percentage:Math.round(s/r*100)}),a.resize(n),r=n,t.info("Map size grown successfully",{new_map_size:n,new_map_size_gb:Math.round(n/(1024*1024*1024)*100)/100}))}catch(e){t.error("Failed to check/grow map_size",{error:e.message})}},x=()=>{if(!a)throw new Error("Database not initialized. Call initialize_database first.");return a},M=()=>`${Date.now()}-${Math.random().toString(36).substr(2,9)}`,S=(t,e,s)=>`${t}:${e}:${s}`,D=t=>{const e=t.split(":");return{database:e[0],collection:e[1],document_id:e.slice(2).join(":")}},$=async(t=!1)=>{const e=_(),s=o;if(a){try{await new Promise(i=>setTimeout(i,100)),w(),b(),await a.close(),e.info("Database closed successfully")}catch(i){e.warn("Error closing database",{error:i.message})}a=null,r=null,o=null}if(t&&s&&c(s))try{u(s)&&(d(s,{recursive:!0,force:!0}),e.info("Test database directory removed",{path:s}))}catch(i){e.warn("Failed to remove test database directory",{path:s,error:i.message})}},c=t=>t&&(t.includes("test_data")||t.startsWith("./test_")||t.startsWith("test_"));export{S as build_collection_key,k as check_and_grow_map_size,$ as cleanup_database,M as generate_document_id,x as get_database,y as initialize_database,c as is_test_database_path,D as parse_collection_key};
1
+ import*as l from"lmdb";import{rmSync as d,existsSync as m}from"fs";import{randomBytes as u}from"crypto";import p from"./logger.js";import{calculate_map_size as f,get_disk_size as g,should_grow_map_size as z}from"./disk_utils.js";import{initialize_index_database as b,cleanup_index_database as h}from"./index_manager.js";import{initialize_auto_index_database as w,cleanup_auto_index_database as y}from"./auto_index_manager.js";const{create_context_logger:c}=p("query_engine");let r=null,i=null,o=null;const k=(t="./data")=>{const e=c();return r||(o=t,f(o).then(s=>{i=s,r&&r.resize&&(r.resize(i),e.info("Database map_size updated",{path:o,map_size:i,map_size_gb:Math.round(i/(1024*1024*1024)*100)/100}))}).catch(s=>{e.warn("Failed to calculate map_size, using default",{database_path:o,error:s.message})}),i=1024*1024*1024*10,r=l.open({path:o,compression:!0,useVersions:!1,encoding:"msgpack",mapSize:i}),e.info("Database initialized",{path:o,map_size:i,map_size_gb:Math.round(i/(1024*1024*1024)*100)/100}),b(),w()),r},x=async()=>{if(!r||!o)return;const t=c();try{const e=r.getStats?r.getStats():{},a=e.ms_psize*e.ms_leaf_pages||0;if(a===0)return;const s=await g(o),n=z(i,a,s);n&&(t.info("Growing map_size",{current_map_size:i,new_map_size:n,used_size:a,usage_percentage:Math.round(a/i*100)}),r.resize(n),i=n,t.info("Map size grown successfully",{new_map_size:n,new_map_size_gb:Math.round(n/(1024*1024*1024)*100)/100}))}catch(e){t.error("Failed to check/grow map_size",{error:e.message})}},M=()=>{if(!r)throw new Error("Database not initialized. Call initialize_database first.");return r},S=()=>{const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",e=u(16);let a="";for(let s=0;s<16;s++)a+=t.charAt(e[s]%t.length);return a},v=(t,e,a)=>`${t}:${e}:${a}`,D=t=>{const e=t.split(":");return{database:e[0],collection:e[1],document_id:e.slice(2).join(":")}},F=async(t=!1)=>{const e=c(),a=o;if(r){try{await new Promise(s=>setTimeout(s,100)),y(),h(),await r.close(),e.info("Database closed successfully")}catch(s){e.warn("Error closing database",{error:s.message})}r=null,i=null,o=null}if(t&&a&&_(a))try{m(a)&&(d(a,{recursive:!0,force:!0}),e.info("Test database directory removed",{path:a}))}catch(s){e.warn("Failed to remove test database directory",{path:a,error:s.message})}},_=t=>t&&(t.includes("test_data")||t.startsWith("./test_")||t.startsWith("test_"));export{v as build_collection_key,x as check_and_grow_map_size,F as cleanup_database,S as generate_document_id,M as get_database,k as initialize_database,_ as is_test_database_path,D as parse_collection_key};
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.2229",
5
- "canary_version": "0.0.0-canary.2228",
4
+ "version": "0.0.0-canary.2231",
5
+ "canary_version": "0.0.0-canary.2230",
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
  /**
@@ -8,6 +8,7 @@
8
8
 
9
9
  import * as lmdb from 'lmdb';
10
10
  import { rmSync, existsSync } from 'fs';
11
+ import { randomBytes } from 'crypto';
11
12
  import create_logger from './logger.js';
12
13
  import { calculate_map_size, get_disk_size, should_grow_map_size } from './disk_utils.js';
13
14
  import { initialize_index_database, cleanup_index_database } from './index_manager.js';
@@ -135,11 +136,19 @@ const get_database = () => {
135
136
  };
136
137
 
137
138
  /**
138
- * Generates a unique document ID using timestamp and random string.
139
- * @returns {string} Unique document identifier
139
+ * Generates a unique document ID as a 16-character alphanumeric string using cryptographically secure randomization.
140
+ * @returns {string} Unique document identifier (16 alphanumeric characters)
140
141
  */
141
142
  const generate_document_id = () => {
142
- return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
143
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
144
+ const random_bytes = randomBytes(16);
145
+ let result = '';
146
+
147
+ for (let i = 0; i < 16; i++) {
148
+ result += characters.charAt(random_bytes[i] % characters.length);
149
+ }
150
+
151
+ return result;
143
152
  };
144
153
 
145
154
  /**
@@ -38,6 +38,35 @@ test('query_engine - should generate unique document ids', (t) => {
38
38
  t.not(id1, id2);
39
39
  });
40
40
 
41
+ test('query_engine - should generate 16-character alphanumeric document ids', (t) => {
42
+ const id = generate_document_id();
43
+
44
+ // Should be exactly 16 characters
45
+ t.is(id.length, 16);
46
+
47
+ // Should only contain alphanumeric characters (A-Z, a-z, 0-9)
48
+ const alphanumeric_regex = /^[A-Za-z0-9]+$/;
49
+ t.true(alphanumeric_regex.test(id));
50
+
51
+ // Should not contain hyphens or other punctuation
52
+ t.false(id.includes('-'));
53
+ t.false(id.includes('_'));
54
+ t.false(id.includes('.'));
55
+ });
56
+
57
+ test('query_engine - should generate cryptographically secure document ids', (t) => {
58
+ // Generate multiple IDs to check for randomness
59
+ const ids = new Set();
60
+ for (let i = 0; i < 1000; i++) {
61
+ const id = generate_document_id();
62
+ t.false(ids.has(id), `Duplicate ID generated: ${id}`);
63
+ ids.add(id);
64
+ }
65
+
66
+ // All IDs should be unique
67
+ t.is(ids.size, 1000);
68
+ });
69
+
41
70
  test('query_engine - should build and parse collection keys correctly', (t) => {
42
71
  const key = build_collection_key('default', 'users', 'abc123');
43
72
  t.is(key, 'default:users:abc123');