axiodb 7.33.233 → 7.33.234
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.
- package/.agents/skills/axiodb-development/SKILL.md +284 -0
- package/.gemini/settings.json +53 -0
- package/lib/Helper/DocumentLoader.helper.d.ts +45 -0
- package/lib/Helper/DocumentLoader.helper.js +91 -0
- package/lib/Helper/DocumentLoader.helper.js.map +1 -0
- package/lib/Helper/PathSanitizer.helper.d.ts +69 -0
- package/lib/Helper/PathSanitizer.helper.js +113 -0
- package/lib/Helper/PathSanitizer.helper.js.map +1 -0
- package/lib/Services/Aggregation/Aggregation.Operation.js +8 -20
- package/lib/Services/Aggregation/Aggregation.Operation.js.map +1 -1
- package/lib/Services/CRUD Operation/Create.operation.js +7 -2
- package/lib/Services/CRUD Operation/Create.operation.js.map +1 -1
- package/lib/Services/CRUD Operation/Delete.operation.d.ts +1 -0
- package/lib/Services/CRUD Operation/Delete.operation.js +11 -62
- package/lib/Services/CRUD Operation/Delete.operation.js.map +1 -1
- package/lib/Services/CRUD Operation/Reader.operation.js +13 -29
- package/lib/Services/CRUD Operation/Reader.operation.js.map +1 -1
- package/lib/Services/CRUD Operation/Update.operation.d.ts +1 -0
- package/lib/Services/CRUD Operation/Update.operation.js +11 -62
- package/lib/Services/CRUD Operation/Update.operation.js.map +1 -1
- package/lib/Services/Database/database.operation.js +5 -2
- package/lib/Services/Database/database.operation.js.map +1 -1
- package/lib/engine/Filesystem/FileManager.d.ts +13 -0
- package/lib/engine/Filesystem/FileManager.js +49 -0
- package/lib/engine/Filesystem/FileManager.js.map +1 -1
- package/package.json +1 -1
- package/.antigravity/rules.md +0 -228
- package/.cursorrules +0 -60
- package/AI_TOOLS_SETUP.md +0 -368
- /package/.cursor/rules/{axiodb-core.md → axiodb-core.mdc} +0 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: axiodb-development
|
|
3
|
+
description: Core development rules and patterns for AxioDB embedded NoSQL database
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags: [typescript, database, testing, build]
|
|
6
|
+
author: AxioDB Team
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# AxioDB Development Skill
|
|
10
|
+
|
|
11
|
+
## Project Identity
|
|
12
|
+
|
|
13
|
+
**AxioDB** - Embedded NoSQL database for Node.js
|
|
14
|
+
- TypeScript strict mode → CommonJS
|
|
15
|
+
- Node.js ≥20.0.0
|
|
16
|
+
- Zero native dependencies
|
|
17
|
+
- Singleton pattern, file-per-document storage
|
|
18
|
+
|
|
19
|
+
## Mandatory Workflows
|
|
20
|
+
|
|
21
|
+
### After EVERY Code Change
|
|
22
|
+
```bash
|
|
23
|
+
npm run build # MANDATORY - catch TypeScript errors immediately
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### For ANY Feature Change
|
|
27
|
+
1. Update tests in `Test/modules/`
|
|
28
|
+
2. Run `npm test` - all tests must pass
|
|
29
|
+
3. Update docs (README.md, Document/, Dockerfile)
|
|
30
|
+
4. Run `npm run lint` - must pass
|
|
31
|
+
|
|
32
|
+
## Definition of "Done"
|
|
33
|
+
|
|
34
|
+
A task is NOT complete until ALL of these are true:
|
|
35
|
+
- ✅ Code written following standards
|
|
36
|
+
- ✅ `npm run build` passes with zero errors
|
|
37
|
+
- ✅ Tests added/updated in `Test/modules/`
|
|
38
|
+
- ✅ `npm test` passes - all tests green
|
|
39
|
+
- ✅ `npm run lint` passes
|
|
40
|
+
- ✅ Documentation updated (README, Document/, Dockerfile)
|
|
41
|
+
- ✅ No breaking changes (or explicitly noted and approved)
|
|
42
|
+
- ✅ Self-reviewed for performance, security, maintainability
|
|
43
|
+
|
|
44
|
+
## Architecture Constraints
|
|
45
|
+
|
|
46
|
+
### Singleton Pattern (NON-NEGOTIABLE)
|
|
47
|
+
```typescript
|
|
48
|
+
export class AxioDB {
|
|
49
|
+
private static _instance: AxioDB;
|
|
50
|
+
|
|
51
|
+
constructor() {
|
|
52
|
+
if (AxioDB._instance) {
|
|
53
|
+
throw new Error("Only one instance of AxioDB is allowed.");
|
|
54
|
+
}
|
|
55
|
+
AxioDB._instance = this;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Critical Implication**: Tests MUST run in separate child processes. Cannot run tests in parallel.
|
|
61
|
+
|
|
62
|
+
### File-Per-Document Storage
|
|
63
|
+
```
|
|
64
|
+
{RootPath}/{DatabaseName}/{CollectionName}/{documentId}.axiodb
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Dual-Write Pattern (Indexes)
|
|
68
|
+
```typescript
|
|
69
|
+
// ALWAYS write to BOTH memory AND disk
|
|
70
|
+
await this.indexCache.set(key, data, TTL); // Memory (speed)
|
|
71
|
+
await this.fileManager.writeFile(path, JSON.stringify(data)); // Disk (durability)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Random Cache TTL (5-15 minutes)
|
|
75
|
+
```typescript
|
|
76
|
+
const TTL = Math.floor(Math.random() * (15 - 5 + 1) + 5) * 60 * 1000;
|
|
77
|
+
```
|
|
78
|
+
**Why**: Prevents cache stampede/thundering herd
|
|
79
|
+
|
|
80
|
+
## TypeScript Standards (STRICT)
|
|
81
|
+
|
|
82
|
+
### NO `any` Types - EVER
|
|
83
|
+
```typescript
|
|
84
|
+
// ❌ ABSOLUTELY FORBIDDEN
|
|
85
|
+
const result: any = await operation();
|
|
86
|
+
|
|
87
|
+
// ✅ REQUIRED
|
|
88
|
+
interface OperationResult {
|
|
89
|
+
success: boolean;
|
|
90
|
+
data: DocumentData;
|
|
91
|
+
}
|
|
92
|
+
const result: OperationResult = await operation();
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Strict Null Checks
|
|
96
|
+
```typescript
|
|
97
|
+
// ✅ GOOD
|
|
98
|
+
function get(id: string): Document | null {
|
|
99
|
+
return this.cache.get(id) ?? null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const doc = get('123');
|
|
103
|
+
if (doc !== null) {
|
|
104
|
+
console.log(doc.name);
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## SOLID Principles
|
|
109
|
+
|
|
110
|
+
### Single Responsibility
|
|
111
|
+
Each class/module has ONE reason to change.
|
|
112
|
+
|
|
113
|
+
### Don't Repeat Yourself (DRY)
|
|
114
|
+
If same logic appears in 2+ files, extract to `Helper/` directory.
|
|
115
|
+
|
|
116
|
+
### No Hacky Solutions
|
|
117
|
+
```typescript
|
|
118
|
+
// ❌ FORBIDDEN
|
|
119
|
+
setTimeout(() => { /* hope this works */ }, 1000);
|
|
120
|
+
eval(userInput);
|
|
121
|
+
try { risky(); } catch (e) { /* ignore */ }
|
|
122
|
+
|
|
123
|
+
// ✅ REQUIRED
|
|
124
|
+
await properAsyncOperation();
|
|
125
|
+
const sanitized = validateAndSanitize(userInput);
|
|
126
|
+
try { await risky(); } catch (error) {
|
|
127
|
+
logger.error('Operation failed', error);
|
|
128
|
+
return ResponseHelper.error('Failed', StatusCodes.ERROR);
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Testing Requirements
|
|
133
|
+
|
|
134
|
+
### Location
|
|
135
|
+
```
|
|
136
|
+
Test/modules/
|
|
137
|
+
├── crud.test.js # CRUD operations
|
|
138
|
+
├── transaction.test.js # Transactions, WAL, savepoints
|
|
139
|
+
└── read.test.js # Read optimizations, caching
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Coverage Required
|
|
143
|
+
- Happy path (success scenarios)
|
|
144
|
+
- Edge cases (empty, null, undefined, large data)
|
|
145
|
+
- Error cases (validation failures, file errors, conflicts)
|
|
146
|
+
- Concurrent operations
|
|
147
|
+
- Backward compatibility
|
|
148
|
+
|
|
149
|
+
## Module Organization
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
source/
|
|
153
|
+
├── Services/
|
|
154
|
+
│ ├── Database/ # Database ops
|
|
155
|
+
│ ├── Collection/ # Collection ops
|
|
156
|
+
│ ├── CRUD Operation/ # Create, Reader, Update, Delete
|
|
157
|
+
│ ├── Index/ # Index management (cache + disk)
|
|
158
|
+
│ ├── Aggregation/ # MongoDB-style pipelines
|
|
159
|
+
│ └── Transaction/ # ACID, WAL, sessions
|
|
160
|
+
├── engine/Filesystem/ # FileManager, FolderManager
|
|
161
|
+
├── server/ # HTTP GUI (Fastify, port 27018)
|
|
162
|
+
├── tcp/ # TCP server (AxioDBCloud, port 27019)
|
|
163
|
+
├── client/ # AxioDBCloud TCP client
|
|
164
|
+
├── Helper/ # Converter, Crypto, Response
|
|
165
|
+
└── Memory/ # InMemoryCache
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Naming Conventions
|
|
169
|
+
|
|
170
|
+
- **Files**: `{Feature}.operation.ts`, `{Feature}.service.ts`, `{Feature}.helper.ts`
|
|
171
|
+
- **Classes**: PascalCase: `FileManager`, `QueryMatcher`
|
|
172
|
+
- **Methods**: camelCase: `createDatabase()`, `isValidDocument()`
|
|
173
|
+
- **Variables**: camelCase: `documentId`, `collectionPath`
|
|
174
|
+
|
|
175
|
+
## Performance Standards
|
|
176
|
+
|
|
177
|
+
### 1. Use InMemoryCache
|
|
178
|
+
```typescript
|
|
179
|
+
const cached = this.cache.get(key);
|
|
180
|
+
if (cached) return cached;
|
|
181
|
+
|
|
182
|
+
const data = await this.readFromDisk(id);
|
|
183
|
+
this.cache.set(key, data, TTL);
|
|
184
|
+
return data;
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 2. Batch Operations
|
|
188
|
+
```typescript
|
|
189
|
+
// ✅ PARALLEL
|
|
190
|
+
await Promise.all(docs.map(d => this.insert(d)));
|
|
191
|
+
|
|
192
|
+
// ❌ SEQUENTIAL (slow)
|
|
193
|
+
for (const d of docs) { await this.insert(d); }
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### 3. Use Map for O(1) Lookups
|
|
197
|
+
```typescript
|
|
198
|
+
// ✅ O(1)
|
|
199
|
+
const map = new Map<string, Document>();
|
|
200
|
+
const found = map.get(id);
|
|
201
|
+
|
|
202
|
+
// ❌ O(n)
|
|
203
|
+
const found = array.find(d => d.id === id);
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Security Standards
|
|
207
|
+
|
|
208
|
+
### 1. Validate All Input
|
|
209
|
+
```typescript
|
|
210
|
+
if (!document || typeof document !== 'object') {
|
|
211
|
+
return this.ResponseHelper.error('Invalid', StatusCodes.BAD_REQUEST);
|
|
212
|
+
}
|
|
213
|
+
if (Array.isArray(document)) {
|
|
214
|
+
return this.ResponseHelper.error('Cannot be array', StatusCodes.BAD_REQUEST);
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 2. Sanitize File Paths
|
|
219
|
+
```typescript
|
|
220
|
+
// Prevent path traversal
|
|
221
|
+
const sanitized = documentId.replace(/[^a-zA-Z0-9-_]/g, '_');
|
|
222
|
+
return path.join(collectionPath, `${sanitized}.axiodb`);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### 3. Handle Sensitive Data
|
|
226
|
+
```typescript
|
|
227
|
+
// Encrypt collections with sensitive data
|
|
228
|
+
const users = await db.createCollection('Users', true, process.env.KEY);
|
|
229
|
+
|
|
230
|
+
// Never log passwords
|
|
231
|
+
logger.info('Auth', { userId }); // ✅
|
|
232
|
+
logger.info('Auth', { password }); // ❌
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Documentation Requirements
|
|
236
|
+
|
|
237
|
+
Update when features change:
|
|
238
|
+
|
|
239
|
+
1. **README.md** - Public API, features, quick start examples
|
|
240
|
+
2. **Document/** - React docs site (`cd Document && npm run dev`)
|
|
241
|
+
3. **Dockerfile** - If ports, env vars, or commands change
|
|
242
|
+
4. **JSDoc** - All public methods with examples
|
|
243
|
+
|
|
244
|
+
## Anti-Patterns (FORBIDDEN)
|
|
245
|
+
|
|
246
|
+
❌ Using `any` types
|
|
247
|
+
❌ Duplicated code (violates DRY)
|
|
248
|
+
❌ Sequential operations that could be parallel
|
|
249
|
+
❌ Ignoring build errors
|
|
250
|
+
❌ Skipping tests
|
|
251
|
+
❌ Missing documentation
|
|
252
|
+
❌ Hardcoded values
|
|
253
|
+
❌ Magic strings/numbers
|
|
254
|
+
❌ Deep nesting (>3 levels)
|
|
255
|
+
❌ Unclear variable names
|
|
256
|
+
❌ Suppressing errors without handling
|
|
257
|
+
|
|
258
|
+
## Commands
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Build & Test
|
|
262
|
+
npm run build # TypeScript → lib/ (MANDATORY)
|
|
263
|
+
npm test # All tests
|
|
264
|
+
npm test crud # CRUD tests only
|
|
265
|
+
npm test transaction # Transaction tests only
|
|
266
|
+
npm test read # Read optimization tests
|
|
267
|
+
npm run lint # ESLint
|
|
268
|
+
|
|
269
|
+
# Development
|
|
270
|
+
node Test/modules/crud.test.js # Run specific test
|
|
271
|
+
cd Document && npm run dev # Docs site (localhost:5173)
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Success Criteria
|
|
275
|
+
|
|
276
|
+
Every task must meet ALL:
|
|
277
|
+
- ✅ Builds successfully (`npm run build`)
|
|
278
|
+
- ✅ Tests pass (`npm test`)
|
|
279
|
+
- ✅ Lint passes (`npm run lint`)
|
|
280
|
+
- ✅ Docs updated
|
|
281
|
+
- ✅ No regressions
|
|
282
|
+
- ✅ Follows patterns
|
|
283
|
+
- ✅ Security validated
|
|
284
|
+
- ✅ Performance acceptable
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0",
|
|
3
|
+
"description": "NoSQL database management system for efficient data storage and retrieval.",
|
|
4
|
+
"project": {
|
|
5
|
+
"name": "AxioDB",
|
|
6
|
+
"type": "NoSQL Database",
|
|
7
|
+
"language": "TypeScript",
|
|
8
|
+
"runtime": "Node.js ≥18.0.0"
|
|
9
|
+
},
|
|
10
|
+
"context": {
|
|
11
|
+
"fileName": [
|
|
12
|
+
"GEMINI.md"
|
|
13
|
+
],
|
|
14
|
+
"hierarchical": true,
|
|
15
|
+
"scanSubdirectories": true
|
|
16
|
+
},
|
|
17
|
+
"tools": {
|
|
18
|
+
"enabled": [
|
|
19
|
+
"codeSearch",
|
|
20
|
+
"fileOperations",
|
|
21
|
+
"shellCommands"
|
|
22
|
+
],
|
|
23
|
+
"codeSearch": {
|
|
24
|
+
"indexFiles": true,
|
|
25
|
+
"excludePatterns": [
|
|
26
|
+
"node_modules",
|
|
27
|
+
"lib",
|
|
28
|
+
"dist",
|
|
29
|
+
".git"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"safety": {
|
|
34
|
+
"blockNone": false,
|
|
35
|
+
"blockFewUnsafe": true,
|
|
36
|
+
"blockSomeUnsafe": true,
|
|
37
|
+
"blockMostUnsafe": true
|
|
38
|
+
},
|
|
39
|
+
"performance": {
|
|
40
|
+
"streamResponse": true,
|
|
41
|
+
"cacheContext": true,
|
|
42
|
+
"maxCachedContexts": 10
|
|
43
|
+
},
|
|
44
|
+
"features": {
|
|
45
|
+
"codeCompletion": true,
|
|
46
|
+
"codeGeneration": true,
|
|
47
|
+
"codeExplanation": true,
|
|
48
|
+
"debugging": true,
|
|
49
|
+
"refactoring": true,
|
|
50
|
+
"testing": true,
|
|
51
|
+
"documentation": true
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { SuccessInterface, ErrorInterface } from '../config/Interfaces/Helper/response.helper.interface';
|
|
2
|
+
/**
|
|
3
|
+
* DocumentLoader - Shared utility for loading documents from collection directories
|
|
4
|
+
*
|
|
5
|
+
* Provides a centralized method for loading document files using worker threads,
|
|
6
|
+
* replacing duplicated code in Reader, Update, Delete, and Aggregation operations.
|
|
7
|
+
*
|
|
8
|
+
* @class DocumentLoader
|
|
9
|
+
*/
|
|
10
|
+
export default class DocumentLoader {
|
|
11
|
+
private static readonly ResponseHelper;
|
|
12
|
+
/**
|
|
13
|
+
* Loads all documents from a collection directory using worker threads
|
|
14
|
+
*
|
|
15
|
+
* This method consolidates the LoadAllBufferRawData logic that was previously
|
|
16
|
+
* duplicated across multiple CRUD operations. It handles both direct file
|
|
17
|
+
* specification and directory scanning with .axiodb file filtering.
|
|
18
|
+
*
|
|
19
|
+
* @param collectionPath - Full path to collection directory
|
|
20
|
+
* @param encryptionKey - Optional encryption key for encrypted documents
|
|
21
|
+
* @param isEncrypted - Whether documents are encrypted (default: false)
|
|
22
|
+
* @param documentFiles - Optional specific file names to load
|
|
23
|
+
* @param includeFileName - Whether to include fileName in result (default: false)
|
|
24
|
+
* @returns Success with document array or Error
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // Load all documents from a collection
|
|
28
|
+
* const result = await DocumentLoader.loadDocuments(
|
|
29
|
+
* '/path/to/collection',
|
|
30
|
+
* undefined,
|
|
31
|
+
* false
|
|
32
|
+
* );
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Load specific documents with filenames included
|
|
36
|
+
* const result = await DocumentLoader.loadDocuments(
|
|
37
|
+
* '/path/to/collection',
|
|
38
|
+
* 'encryption-key',
|
|
39
|
+
* true,
|
|
40
|
+
* ['doc1.axiodb', 'doc2.axiodb'],
|
|
41
|
+
* true
|
|
42
|
+
* );
|
|
43
|
+
*/
|
|
44
|
+
static loadDocuments(collectionPath: string, encryptionKey?: string, isEncrypted?: boolean, documentFiles?: string[], includeFileName?: boolean): Promise<SuccessInterface | ErrorInterface>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const FolderManager_1 = __importDefault(require("../engine/Filesystem/FolderManager"));
|
|
16
|
+
const BufferLoaderWithWorker_utils_1 = __importDefault(require("../utility/BufferLoaderWithWorker.utils"));
|
|
17
|
+
const response_helper_1 = __importDefault(require("./response.helper"));
|
|
18
|
+
/**
|
|
19
|
+
* DocumentLoader - Shared utility for loading documents from collection directories
|
|
20
|
+
*
|
|
21
|
+
* Provides a centralized method for loading document files using worker threads,
|
|
22
|
+
* replacing duplicated code in Reader, Update, Delete, and Aggregation operations.
|
|
23
|
+
*
|
|
24
|
+
* @class DocumentLoader
|
|
25
|
+
*/
|
|
26
|
+
class DocumentLoader {
|
|
27
|
+
/**
|
|
28
|
+
* Loads all documents from a collection directory using worker threads
|
|
29
|
+
*
|
|
30
|
+
* This method consolidates the LoadAllBufferRawData logic that was previously
|
|
31
|
+
* duplicated across multiple CRUD operations. It handles both direct file
|
|
32
|
+
* specification and directory scanning with .axiodb file filtering.
|
|
33
|
+
*
|
|
34
|
+
* @param collectionPath - Full path to collection directory
|
|
35
|
+
* @param encryptionKey - Optional encryption key for encrypted documents
|
|
36
|
+
* @param isEncrypted - Whether documents are encrypted (default: false)
|
|
37
|
+
* @param documentFiles - Optional specific file names to load
|
|
38
|
+
* @param includeFileName - Whether to include fileName in result (default: false)
|
|
39
|
+
* @returns Success with document array or Error
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* // Load all documents from a collection
|
|
43
|
+
* const result = await DocumentLoader.loadDocuments(
|
|
44
|
+
* '/path/to/collection',
|
|
45
|
+
* undefined,
|
|
46
|
+
* false
|
|
47
|
+
* );
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // Load specific documents with filenames included
|
|
51
|
+
* const result = await DocumentLoader.loadDocuments(
|
|
52
|
+
* '/path/to/collection',
|
|
53
|
+
* 'encryption-key',
|
|
54
|
+
* true,
|
|
55
|
+
* ['doc1.axiodb', 'doc2.axiodb'],
|
|
56
|
+
* true
|
|
57
|
+
* );
|
|
58
|
+
*/
|
|
59
|
+
static loadDocuments(collectionPath_1, encryptionKey_1) {
|
|
60
|
+
return __awaiter(this, arguments, void 0, function* (collectionPath, encryptionKey, isEncrypted = false, documentFiles, includeFileName = false) {
|
|
61
|
+
try {
|
|
62
|
+
const dataFilesList = [];
|
|
63
|
+
if (documentFiles !== undefined) {
|
|
64
|
+
// Use provided file list
|
|
65
|
+
dataFilesList.push(...documentFiles);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// Scan directory for .axiodb files
|
|
69
|
+
const readResponse = yield new FolderManager_1.default().ListDirectory(collectionPath);
|
|
70
|
+
if ("data" in readResponse) {
|
|
71
|
+
// Filter for .axiodb files only
|
|
72
|
+
const axiodbFiles = readResponse.data.filter((file) => file.endsWith(".axiodb"));
|
|
73
|
+
dataFilesList.push(...axiodbFiles);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
return this.ResponseHelper.Error("Failed to read directory");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Load all files using worker threads (parallel processing)
|
|
80
|
+
const resultData = yield (0, BufferLoaderWithWorker_utils_1.default)(dataFilesList, encryptionKey, collectionPath, isEncrypted, includeFileName);
|
|
81
|
+
return this.ResponseHelper.Success(resultData);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return this.ResponseHelper.Error(error);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
DocumentLoader.ResponseHelper = new response_helper_1.default();
|
|
90
|
+
exports.default = DocumentLoader;
|
|
91
|
+
//# sourceMappingURL=DocumentLoader.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DocumentLoader.helper.js","sourceRoot":"","sources":["../../source/Helper/DocumentLoader.helper.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AACA,uFAA+D;AAC/D,2GAAuE;AACvE,wEAA+C;AAE/C;;;;;;;GAOG;AACH,MAAqB,cAAc;IAGjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,MAAM,CAAO,aAAa;6DACxB,cAAsB,EACtB,aAAsB,EACtB,cAAuB,KAAK,EAC5B,aAAwB,EACxB,kBAA2B,KAAK;YAEhC,IAAI,CAAC;gBACH,MAAM,aAAa,GAAa,EAAE,CAAC;gBAEnC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;oBAChC,yBAAyB;oBACzB,aAAa,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;gBACvC,CAAC;qBAAM,CAAC;oBACN,mCAAmC;oBACnC,MAAM,YAAY,GAAG,MAAM,IAAI,uBAAa,EAAE,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC;oBAE7E,IAAI,MAAM,IAAI,YAAY,EAAE,CAAC;wBAC3B,gCAAgC;wBAChC,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE,CAC5D,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CACzB,CAAC;wBACF,aAAa,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;oBACrC,CAAC;yBAAM,CAAC;wBACN,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;oBAC/D,CAAC;gBACH,CAAC;gBAED,4DAA4D;gBAC5D,MAAM,UAAU,GAAG,MAAM,IAAA,sCAAgB,EACvC,aAAa,EACb,aAAa,EACb,cAAc,EACd,WAAW,EACX,eAAe,CAChB,CAAC;gBAEF,OAAO,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YACjD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;KAAA;;AA3EuB,6BAAc,GAAG,IAAI,yBAAc,EAAE,CAAC;kBAD3C,cAAc"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PathSanitizer - Security helper to prevent directory traversal attacks
|
|
3
|
+
*
|
|
4
|
+
* Provides methods to sanitize user-controlled path components and validate
|
|
5
|
+
* that constructed paths remain within expected boundaries.
|
|
6
|
+
*
|
|
7
|
+
* @class PathSanitizer
|
|
8
|
+
* @example
|
|
9
|
+
* const safe = PathSanitizer.sanitizePathComponent('../../etc/passwd');
|
|
10
|
+
* // Returns: '______etc_passwd'
|
|
11
|
+
*/
|
|
12
|
+
export default class PathSanitizer {
|
|
13
|
+
/**
|
|
14
|
+
* Sanitizes user input to prevent directory traversal attacks
|
|
15
|
+
*
|
|
16
|
+
* Removes dangerous characters that could be used for path traversal,
|
|
17
|
+
* including: '../', '/', '\', null bytes, and other special characters.
|
|
18
|
+
*
|
|
19
|
+
* @param userInput - Potentially malicious path component
|
|
20
|
+
* @returns Sanitized string safe for file paths
|
|
21
|
+
* @throws Error if input is invalid or results in empty string
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* PathSanitizer.sanitizePathComponent('../../../etc/passwd');
|
|
25
|
+
* // Returns: '______etc_passwd'
|
|
26
|
+
*
|
|
27
|
+
* PathSanitizer.sanitizePathComponent('safe-name_123');
|
|
28
|
+
* // Returns: 'safe-name_123'
|
|
29
|
+
*/
|
|
30
|
+
static sanitizePathComponent(userInput: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Validates that resolved path is within basePath (defense in depth)
|
|
33
|
+
*
|
|
34
|
+
* This provides an additional security layer by ensuring the final
|
|
35
|
+
* constructed path hasn't escaped the expected base directory through
|
|
36
|
+
* symlinks or other means.
|
|
37
|
+
*
|
|
38
|
+
* @param basePath - Expected parent directory
|
|
39
|
+
* @param fullPath - Constructed path to validate
|
|
40
|
+
* @throws Error if path traversal detected
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* PathSanitizer.validatePath('/app/data', '/app/data/users/123.axiodb');
|
|
44
|
+
* // No error - path is within base
|
|
45
|
+
*
|
|
46
|
+
* PathSanitizer.validatePath('/app/data', '/etc/passwd');
|
|
47
|
+
* // Throws: Security violation: Path traversal attempt detected
|
|
48
|
+
*/
|
|
49
|
+
static validatePath(basePath: string, fullPath: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* Safe path join with automatic sanitization and validation
|
|
52
|
+
*
|
|
53
|
+
* Combines base path with one or more path components after sanitizing
|
|
54
|
+
* each component and validating the final path remains within the base.
|
|
55
|
+
*
|
|
56
|
+
* @param basePath - Base directory (trusted path)
|
|
57
|
+
* @param components - Path components to join (will be sanitized)
|
|
58
|
+
* @returns Safe joined path guaranteed to be within basePath
|
|
59
|
+
* @throws Error if sanitization fails or path traversal detected
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* PathSanitizer.safePath('/app/data', 'users', 'doc123.axiodb');
|
|
63
|
+
* // Returns: '/app/data/users/doc123.axiodb'
|
|
64
|
+
*
|
|
65
|
+
* PathSanitizer.safePath('/app/data', '../../../etc/passwd');
|
|
66
|
+
* // Throws: Security violation (after sanitization and validation)
|
|
67
|
+
*/
|
|
68
|
+
static safePath(basePath: string, ...components: string[]): string;
|
|
69
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const path_1 = __importDefault(require("path"));
|
|
7
|
+
/**
|
|
8
|
+
* PathSanitizer - Security helper to prevent directory traversal attacks
|
|
9
|
+
*
|
|
10
|
+
* Provides methods to sanitize user-controlled path components and validate
|
|
11
|
+
* that constructed paths remain within expected boundaries.
|
|
12
|
+
*
|
|
13
|
+
* @class PathSanitizer
|
|
14
|
+
* @example
|
|
15
|
+
* const safe = PathSanitizer.sanitizePathComponent('../../etc/passwd');
|
|
16
|
+
* // Returns: '______etc_passwd'
|
|
17
|
+
*/
|
|
18
|
+
class PathSanitizer {
|
|
19
|
+
/**
|
|
20
|
+
* Sanitizes user input to prevent directory traversal attacks
|
|
21
|
+
*
|
|
22
|
+
* Removes dangerous characters that could be used for path traversal,
|
|
23
|
+
* including: '../', '/', '\', null bytes, and other special characters.
|
|
24
|
+
*
|
|
25
|
+
* @param userInput - Potentially malicious path component
|
|
26
|
+
* @returns Sanitized string safe for file paths
|
|
27
|
+
* @throws Error if input is invalid or results in empty string
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* PathSanitizer.sanitizePathComponent('../../../etc/passwd');
|
|
31
|
+
* // Returns: '______etc_passwd'
|
|
32
|
+
*
|
|
33
|
+
* PathSanitizer.sanitizePathComponent('safe-name_123');
|
|
34
|
+
* // Returns: 'safe-name_123'
|
|
35
|
+
*/
|
|
36
|
+
static sanitizePathComponent(userInput) {
|
|
37
|
+
if (!userInput || typeof userInput !== 'string') {
|
|
38
|
+
throw new Error('Invalid path component: must be a non-empty string');
|
|
39
|
+
}
|
|
40
|
+
// Remove all directory traversal attempts
|
|
41
|
+
let sanitized = userInput
|
|
42
|
+
.replace(/\.\./g, '_') // Remove .. (parent directory)
|
|
43
|
+
.replace(/\//g, '_') // Remove / (Unix path separator)
|
|
44
|
+
.replace(/\\/g, '_') // Remove \ (Windows path separator)
|
|
45
|
+
.replace(/\0/g, '_'); // Remove null bytes
|
|
46
|
+
// Allow only alphanumeric, dash, underscore, and dot (for file extensions)
|
|
47
|
+
// Note: We preserve dots for file extensions but removed '..' above
|
|
48
|
+
sanitized = sanitized.replace(/[^a-zA-Z0-9-_.]/g, '_');
|
|
49
|
+
// Prevent empty result
|
|
50
|
+
if (sanitized.length === 0) {
|
|
51
|
+
throw new Error('Invalid path component: results in empty string after sanitization');
|
|
52
|
+
}
|
|
53
|
+
// Prevent starting with dot (hidden files) to avoid potential issues
|
|
54
|
+
if (sanitized.startsWith('.')) {
|
|
55
|
+
sanitized = '_' + sanitized.substring(1);
|
|
56
|
+
}
|
|
57
|
+
return sanitized;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Validates that resolved path is within basePath (defense in depth)
|
|
61
|
+
*
|
|
62
|
+
* This provides an additional security layer by ensuring the final
|
|
63
|
+
* constructed path hasn't escaped the expected base directory through
|
|
64
|
+
* symlinks or other means.
|
|
65
|
+
*
|
|
66
|
+
* @param basePath - Expected parent directory
|
|
67
|
+
* @param fullPath - Constructed path to validate
|
|
68
|
+
* @throws Error if path traversal detected
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* PathSanitizer.validatePath('/app/data', '/app/data/users/123.axiodb');
|
|
72
|
+
* // No error - path is within base
|
|
73
|
+
*
|
|
74
|
+
* PathSanitizer.validatePath('/app/data', '/etc/passwd');
|
|
75
|
+
* // Throws: Security violation: Path traversal attempt detected
|
|
76
|
+
*/
|
|
77
|
+
static validatePath(basePath, fullPath) {
|
|
78
|
+
const resolvedBase = path_1.default.resolve(basePath);
|
|
79
|
+
const resolvedFull = path_1.default.resolve(fullPath);
|
|
80
|
+
if (!resolvedFull.startsWith(resolvedBase)) {
|
|
81
|
+
throw new Error('Security violation: Path traversal attempt detected');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Safe path join with automatic sanitization and validation
|
|
86
|
+
*
|
|
87
|
+
* Combines base path with one or more path components after sanitizing
|
|
88
|
+
* each component and validating the final path remains within the base.
|
|
89
|
+
*
|
|
90
|
+
* @param basePath - Base directory (trusted path)
|
|
91
|
+
* @param components - Path components to join (will be sanitized)
|
|
92
|
+
* @returns Safe joined path guaranteed to be within basePath
|
|
93
|
+
* @throws Error if sanitization fails or path traversal detected
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* PathSanitizer.safePath('/app/data', 'users', 'doc123.axiodb');
|
|
97
|
+
* // Returns: '/app/data/users/doc123.axiodb'
|
|
98
|
+
*
|
|
99
|
+
* PathSanitizer.safePath('/app/data', '../../../etc/passwd');
|
|
100
|
+
* // Throws: Security violation (after sanitization and validation)
|
|
101
|
+
*/
|
|
102
|
+
static safePath(basePath, ...components) {
|
|
103
|
+
// Sanitize each component
|
|
104
|
+
const sanitizedComponents = components.map(c => this.sanitizePathComponent(c));
|
|
105
|
+
// Join paths using Node.js path.join (handles platform differences)
|
|
106
|
+
const fullPath = path_1.default.join(basePath, ...sanitizedComponents);
|
|
107
|
+
// Validate final path is within base (defense in depth)
|
|
108
|
+
this.validatePath(basePath, fullPath);
|
|
109
|
+
return fullPath;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.default = PathSanitizer;
|
|
113
|
+
//# sourceMappingURL=PathSanitizer.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PathSanitizer.helper.js","sourceRoot":"","sources":["../../source/Helper/PathSanitizer.helper.ts"],"names":[],"mappings":";;;;;AAAA,gDAAwB;AAExB;;;;;;;;;;GAUG;AACH,MAAqB,aAAa;IAChC;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,qBAAqB,CAAC,SAAiB;QAC5C,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,CAAC;QAED,0CAA0C;QAC1C,IAAI,SAAS,GAAG,SAAS;aACtB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAI,+BAA+B;aACxD,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAM,iCAAiC;aAC1D,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAM,oCAAoC;aAC7D,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAK,oBAAoB;QAEhD,2EAA2E;QAC3E,oEAAoE;QACpE,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;QAEvD,uBAAuB;QACvB,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;QACxF,CAAC;QAED,qEAAqE;QACrE,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,SAAS,GAAG,GAAG,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3C,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,YAAY,CAAC,QAAgB,EAAE,QAAgB;QACpD,MAAM,YAAY,GAAG,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,YAAY,GAAG,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAE5C,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAgB,EAAE,GAAG,UAAoB;QACvD,0BAA0B;QAC1B,MAAM,mBAAmB,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;QAE/E,oEAAoE;QACpE,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,mBAAmB,CAAC,CAAC;QAE7D,wDAAwD;QACxD,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAEtC,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAxGD,gCAwGC"}
|