@x12i/xronox
v3.7.3
Published
Data-tier adapter support
Maintainers
Readme
@xronoces/xronox
Version: 3.0.0
Data-tier adapter for the Xronox ecosystem, providing a unified API for reading and writing from databases and storage with support for two engine modes: nx-mongo and @xronoces/xronox-core.
🚀 Env-Ready Component (ERC 2.0)
This component supports zero-config initialization via environment variables using @x12i/env with ERC 2.0 compliance.
Quick Start (ERC 2.0 Mode)
# 1. Install the package
npm install @xronoces/xronox
# 2. Copy .env.example to .env (auto-generated when ERC mode is enabled)
cp node_modules/@xronoces/xronox/.env.example .env
# 3. Fill in required values in .env
# MONGO_URI=mongodb://localhost:27017
# MONGO_DB=myapp
# 4. Use with zero config and ERC 2.0 compliance!
import { createXronox } from '@xronoces/xronox';
const xronox = createXronox();
await xronox.init({
engine: 'nxMongo',
erc: {
enabled: true, // Enable ERC 2.0 compliance
generateManifest: true, // Auto-generate erc-manifest.json
generateEnvExample: true, // Auto-generate .env.example
}
});ERC 2.0 Compliance
- ✅ Auto-discovers configuration from environment variables
- ✅ Type-safe with automatic coercion and validation
- ✅ Transitive requirements automatically documented
- ✅ Automatic manifest and .env.example generation
- ✅ Built-in compliance verification
Verify Compliance:
npm run erc:verifySee ERC 2.0 Standard Documentation for complete details.
🚨 Critical Fixes
1.8.0 - Storage Drivers Implemented - Storage drivers are now fully implemented! xronox supports S3, GCS, Azure Blob, and LocalFS storage via optional driver packages. Storage operations (readObject, writeObject, headObject, listObjects) are now available. See Storage Drivers section for details.
1.7.8 - Result Parsing Bug Fixed - Fixed critical bug where resultInserted always returned 0 despite successful MongoDB inserts. Now correctly parses insertedCount from MongoDB response. See CHANGELOG.md for details.
1.7.7 - Database Name Corruption Bug Fixed - Xronox 1.7.7 includes comprehensive multi-layer validation to prevent database name corruption (specifically the § character bug). Database names are now automatically validated and cleaned at 4 critical checkpoints. See docs/RELEASE-1.7.7.md for details.
🚀 Content Scoping Support (New in 3.0.0)
xronox 3.0.0 introduces powerful content scoping features designed for intelligent LLM context management. These features enable efficient document selection, metadata-only queries, and optimized batch loading with up to 90% reduction in LLM context tokens.
Key Features
- ✅ Field Role Mapping - Query documents by semantic roles (title, summary, content) instead of hardcoded field names
- ✅ External Content Loading Control - Control S3 content loading in Mongo+S3 mesh operations
- ✅ Batch Content Loading Optimization - Parallel S3 fetches for efficient batch document processing
- ✅ Storage Metadata Listing - Include metadata in listObjects() calls (single API call vs multiple headObject calls)
- ✅ Partial Content Reads - Range and line-based partial reads for large files
Field Role Mapping
Query documents using semantic roles instead of hardcoded field names. Configure field mappings per collection or globally:
const config: XronoxConfig = {
fieldRoles: {
'documents': {
title: ['name', 'title'],
summary: ['description', 'summary'],
content: ['body', 'content', 'text'],
key: ['_id'],
system: ['_id', 'createdAt', 'updatedAt', '__v']
},
'*': { // Global defaults
title: ['name', 'title', 'label'],
summary: ['description', 'summary', 'excerpt'],
content: ['content', 'body', 'text', 'markdown'],
key: ['_id', 'id'],
system: ['_id', 'createdAt', 'updatedAt', '__v']
}
}
};
// Query using semantic roles
const metadata = await xronox.read({
dataType: 'metadata',
sourceType: 'database',
subSourceType: 'mongo',
source: 'documents',
roles: {
title: true, // Include title fields
summary: true, // Include summary fields
key: true, // Include key fields (_id)
system: false // Exclude system fields
}
});External Content Loading Control
Control whether external content (from S3) is loaded in Mongo+S3 mesh operations:
// PHASE 1: Metadata only (fast, no S3 reads)
const heads = await xronox.read({
dataType: 'metadata',
sourceType: 'database',
subSourceType: 'mongo',
source: 'documents',
roles: { title: true, summary: true, key: true },
loadExternalContent: false // Skip S3 content loading
});
// PHASE 2: Load full content (with S3 reads)
const fullDocuments = await xronox.read({
dataType: 'metadata',
sourceType: 'database',
subSourceType: 'mongo',
source: 'documents',
query: { _id: { $in: selectedIds } },
roles: { content: true, metadata: true },
loadExternalContent: true // Fetch content from S3
});Batch Content Loading
Optimized batch loading with parallel S3 fetches. Up to 10x performance improvement for large document sets:
// Load content for multiple documents efficiently
const docs = await xronox.read({
query: { _id: { $in: selectedIds } }, // 10-100 IDs
loadExternalContent: true
});
// 1 MongoDB query + parallel S3 reads (vs sequential)Storage Metadata Listing
Include metadata in listObjects() calls to reduce API calls:
// Traditional approach: list + multiple head calls
const objects = await xronox.listObjects({ prefix: 'docs/' });
for (const obj of objects.objects) {
const metadata = await xronox.headObject({ key: obj.key });
}
// New approach: single call with metadata
const objectsWithMetadata = await xronox.listObjects({
prefix: 'docs/',
includeMetadata: true // Includes size, lastModified, etag, custom metadata
});Partial Content Reads
Read portions of large files without loading entire content:
// Read first 1KB
const partial = await xronox.readObject({
subSourceType: 's3',
bucket: 'my-bucket',
key: 'docs/large-file.md',
range: { start: 0, end: 1024 }
});
// Read first 50 lines
const lines = await xronox.readObject({
subSourceType: 's3',
bucket: 'my-bucket',
key: 'docs/large-file.md',
lines: { start: 0, count: 50 }
});Performance Benefits
- 10-100x improvement for large document sets through intelligent scoping
- 90% reduction in LLM context tokens through selective field loading
- Parallel S3 fetches eliminate sequential loading bottlenecks
- Single metadata calls replace multiple API requests
Content Scoping Test Suite
Run the comprehensive content scoping test suite:
npm run test:content-scopingThis tests all content scoping features with real MongoDB and S3 operations.
Installation
npm install @xronoces/xronoxFeatures
- Unified API for database and storage operations
- Two engine modes:
nxMongo(direct MongoDB) andxronoxCore(with storage externalization) - Immutable engine selection - chosen at initialization
- Routing and tenancy support with config-driven bindings
- Type-safe TypeScript implementation
- Standardized error handling with error codes
- nx-mongo 3.8.1+ compatibility with database parameter support
- Automatic config resolution - ENV placeholders resolved automatically (via
@x12i/env) - Automatic .env file loading - Loads
.envfiles automatically (via@x12i/env) - 🆕 Lazy initialization - Auto-initialize on first operation (enabled by default)
- 🆕 Config auto-discovery - Automatically find config from common locations
- 🆕 Zero-config mode - Automatically create minimal config from .env file (just add MONGO_URI!)
- 🆕 Minimal config mode - Work with just MongoDB, no storage required
- 🆕 Enhanced troubleshooting - Powered by
nx-troubleshootingfor intelligent error-to-solution matching - 🆕 Smart error detection - Automatic troubleshooting suggestions with fallback chain analysis
- 🆕 Package default configs - Automatic default configuration loading via
@x12i/env - 🆕 Smart config validation - Schema validation with fallback chain support and functionality detection
- 🆕 Database name validation (v1.7.7) - Multi-layer validation system prevents database name corruption with automatic detection and cleanup
- 🆕 Result parsing fix (v1.7.8) - Fixed critical bug where write operations incorrectly reported 0 inserted documents
- 🆕 Storage drivers (v1.8.0) - Full support for S3, GCS, Azure Blob, and LocalFS storage via optional driver packages
- 🆕 Storage operations (v1.8.0) -
readObject,writeObject,headObject,listObjects,writeJson,readJson,objectExistsnow fully implemented - 🆕 Content Manager features (v1.8.0) - Versioned keys, atomic writes, schema registration, search/index helpers
- 🆕 Operation queue for ensured operations (v2.0.2) - Resource-level sequencing for
ensureInsert/ensureUpdatewith pluggable backends (memory/persistent/redis) - 🆕 Role-based configuration (v2.2.0) - Automatic connection string and database name resolution from roles using
@x12i/envOOTB presets. No need to hardcodeuri/db- specify aroleand let xronox resolve from.env - 🆕 Operation-level role parameter (v2.5.0) - Pass
roleas an optional parameter to any read/write operation to override the binding's default database for that specific operation - 🆕 Content Scoping Support (v3.0.0) - Field role mapping, external content loading control, batch optimization, storage metadata listing, and partial content reads for efficient LLM context management
Quick Start
Zero-Config Mode (Easiest!)
Just add MONGO_URI to your .env file and you're ready to go:
# .env
MONGO_URI=mongodb://localhost:27017
MONGO_DB=myappimport { createXronox } from "@xronoces/xronox";
const xronox = createXronox();
// Zero-config: Automatically creates config from .env
await xronox.init({
engine: "nxMongo"
// No config needed! xronox reads MONGO_URI from .env automatically
});
// Start using it immediately
const results = await xronox.read({
dataType: "metadata",
sourceType: "database",
subSourceType: "mongo",
source: "my-collection",
query: {}
});
await xronox.close();With Explicit Config
import { createXronox } from "@xronoces/xronox";
import type { XronoxConfig } from "@xronoces/xronox";
// Config can use ENV placeholders - xronox automatically resolves them using @x12i/env
// You don't need to use @x12i/env directly unless you want to
// Option 1: Traditional explicit config
const config: XronoxConfig = {
connections: {
database: {
mongo: [
{ alias: "mongo-primary", uri: "ENV.MONGO_URI||mongodb://localhost:27017", db: "ENV.MONGO_DB||core" }
]
}
},
bindings: [
{ subSourceType: "mongo", connection: "mongo-primary", defaults: { db: "ENV.MONGO_DB||core" } }
]
};
// Option 2: Role-based config (NEW in 2.2.0) - uri and db are optional!
// Just specify a role and xronox resolves connection string and database name from .env
// const config: XronoxConfig = {
// connections: {
// database: {
// mongo: [
// { alias: "mongo-primary", role: "operational" } // Resolves from .env automatically
// ]
// }
// },
// bindings: [
// { subSourceType: "mongo", connection: "mongo-primary", defaults: { role: "operational" } }
// ]
// };
const xronox = createXronox();
// Initialize with engine mode
await xronox.init({
config,
engine: "nxMongo" // or "xronoxCore"
});
// Self-test: Validate configuration and detect missing components
const testResult = await xronox.selfTest?.();
if (!testResult.passed) {
console.error('Configuration issues:', testResult.issues);
testResult.checks.forEach(check => {
console.log(`${check.status === 'pass' ? '✅' : '❌'} ${check.name}: ${check.message}`);
});
}
// Read data
const results = await xronox.read({
dataType: "metadata",
sourceType: "database",
subSourceType: "mongo",
source: "entities-data",
query: { type: { $eq: "observedIp" } },
project: ["ipAddress", "zones"]
});
// Cleanup
await xronox.close();Engine Modes
nxMongo Engine
Uses nx-mongo (v3.8.1+) for direct MongoDB operations. Supports:
- MongoDB database operations with database name parameter support
- Storage drivers (s3/gcs/azureblob/localfs) - ✅ Now implemented!
Use when: You need direct MongoDB access with config-driven ref mapping and signature-based deduplication.
Note: Compatible with nx-mongo 3.8.1+ which uses database name as a parameter rather than in the connection string.
Storage Drivers
xronox supports multiple storage backends via optional driver packages. Install only the drivers you need:
# For S3-compatible storage (AWS S3, DigitalOcean Spaces, MinIO, Cloudflare R2, etc.)
npm install @xronoces/xronox @xronoces/xronox-storage-s3
# For Google Cloud Storage
npm install @xronoces/xronox @xronoces/xronox-storage-gcs
# For Azure Blob Storage
npm install @xronoces/xronox @xronoces/xronox-storage-azureblob
# For local filesystem storage
npm install @xronoces/xronox @xronoces/xronox-storage-localfsExample S3 Configuration:
const config: XronoxConfig = {
connections: {
storage: {
s3: [{
alias: "s3-main",
region: "us-east-1",
endpoint: "https://s3.amazonaws.com", // Optional, auto-detected
accessKeyId: "ENV.AWS_ACCESS_KEY_ID",
secretAccessKey: "ENV.AWS_SECRET_ACCESS_KEY",
bucketDefault: "my-bucket" // Optional default bucket
}]
}
},
bindings: [
{ subSourceType: "s3", connection: "s3-main" }
]
};
// Now you can use storage operations
await xronox.writeObject({
subSourceType: "s3",
bucket: "my-bucket",
key: "path/to/file.json",
body: JSON.stringify({ data: "value" }),
contentType: "application/json"
});
const data = await xronox.readObject({
subSourceType: "s3",
bucket: "my-bucket",
key: "path/to/file.json",
asText: true
});Note: Currently only S3 storage is supported. GCS, Azure Blob, and LocalFS drivers are coming soon. xronox automatically discovers and uses installed storage drivers. If the S3 driver is not installed, you'll get a helpful warning message in logs and selfTest().
Content Manager Features
xronox includes convenience methods for content management:
JSON Read/Write:
// Write JSON directly
await xronox.writeJson({
subSourceType: "s3",
bucket: "my-bucket",
key: "content/item.json",
data: { title: "My Item", content: "..." }
});
// Read JSON directly
const data = await xronox.readJson({
subSourceType: "s3",
bucket: "my-bucket",
key: "content/item.json"
});Versioned Keys:
const key = xronox.versionKey({
base: "prompts/prompt-123",
version: "v1",
ext: ".md"
});
// Returns: "prompts/prompt-123/v1.md"Object Existence Check:
const exists = await xronox.objectExists({
subSourceType: "s3",
bucket: "my-bucket",
key: "path/to/file.json"
});
const metadata = await xronox.headObject({
subSourceType: "s3",
bucket: "my-bucket",
key: "path/to/file.json"
});
// Returns: { exists, size, contentType, lastModified, etag, metadata }Atomic Writes:
await xronox.atomicWrite({
meta: {
collection: "content.items",
query: { id: "item-123" },
update: { version: "v1", updatedAt: new Date() },
mode: "replace",
keys: ["id"]
},
storage: {
subSourceType: "s3",
bucket: "my-bucket",
key: "content/item-123/v1.json",
body: JSON.stringify({ data: "..." }),
contentType: "application/json"
}
});List Objects:
const result = await xronox.listObjects({
subSourceType: "s3",
bucket: "my-bucket",
prefix: "content/item-123/",
maxKeys: 100
});
// Returns: { objects: [{ key, size?, lastModified?, etag? }], continuationToken?, isTruncated }
// Note: listObjects returns keys by default. For full metadata, use headObject on individual keys.Upsert Operations:
// Upsert documents - update if exists, insert if not
// Using explicit "upsert" mode (recommended for clarity)
const result = await xronox.write({
dataType: "metadata",
sourceType: "database",
subSourceType: "mongo",
source: "users",
mode: "upsert", // or "replace" - both work the same way
keys: ["email"], // Documents are matched by these keys
documents: [
{ email: "[email protected]", name: "John Doe", updatedAt: new Date() },
{ email: "[email protected]", name: "Admin User", updatedAt: new Date() }
]
});
// Returns: { inserted: 0, replaced: 0, upserted: 2 }
// If document has _id, it's used for matching first
await xronox.write({
dataType: "metadata",
sourceType: "database",
subSourceType: "mongo",
source: "users",
mode: "upsert",
keys: ["email"], // Fallback if _id not found
documents: [
{ _id: "existing-id", email: "[email protected]", name: "Updated Name" }
]
});Read Array Convenience Method:
// read() may return an array or AsyncIterable
const results = await xronox.read({...});
// Need to handle both cases:
let resultsArray: unknown[];
if (Array.isArray(results)) {
resultsArray = results;
} else {
resultsArray = [];
for await (const item of results) {
resultsArray.push(item);
}
}
// Use readArray() for convenience - always returns an array
const resultsArray = await xronox.readArray({
dataType: "metadata",
sourceType: "database",
subSourceType: "mongo",
source: "users",
query: { active: true }
});
// Always returns: unknown[]Search and Indexes:
// Create text index
await xronox.createIndex({
collection: "prompts",
keys: { title: "text", description: "text" },
options: {
weights: { title: 10, description: 1 },
default_language: "english"
}
});
// Search with text
const results = await xronox.search({
dataType: "metadata",
sourceType: "database",
subSourceType: "mongo",
source: "prompts",
text: "deploy application",
searchFields: ["title", "description"],
limit: 10
});xronoxCore Engine
Uses @xronoces/xronox-core (v2.4.0+) for CRUD operations with storage externalization. Supports:
- MongoDB via xronox-core (with automatic storage externalization)
- Versioning and audit trails
- Optimistic locking
- Lazy collection creation - Collections created automatically on first write
- Natural head collection UX - Work with
*-headcollections like normal MongoDB collections
Use when: You need storage externalization, versioning, and audit trails.
Note: xronox-core 2.4.0+ supports lazy collection creation, allowing you to start using collections immediately without pre-creating backing collections (versions, storage, etc.). Collections are created automatically on first write based on configuration.
Storage Operations: Storage operations (readObject, writeObject, headObject, listObjects) are not yet implemented for xronoxCore engine. Use nxMongo engine if you need direct storage operations.
Ensured Operations (New in 1.11.0)
For critical operations that require guaranteed persistence, xronox provides ensureInsert() and ensureUpdate() methods that verify document existence after write operations.
Problem
When writes are queued or delayed, updates can silently fail to apply, leaving records in inconsistent states. Ensured operations provide deterministic feedback that a write actually landed.
Queue-Based Operation Sequencing (New in 2.0.2)
Starting in 2.0.2, ensureInsert() and ensureUpdate() run through a resource-level operation queue:
- Operations targeting the same resource (same
dataType,sourceType,subSourceType,source) execute sequentially. - Operations targeting different resources can execute in parallel.
- Only ensured operations use this queue; regular
write()calls continue to use the existing local queue/batching system.
Configuration is via the optional queue section on XronoxConfig:
const config: XronoxConfig = {
// ...
queue: {
enabled: true, // Default: true
backend: "memory", // "memory" | "persistent" | "redis" (default: "memory")
workers: {
perResource: 1,
retryAttempts: 3,
retryDelay: 1000,
},
},
};See docs/operation-queue.md for full details.
ensureInsert()
Write a document and verify it exists before returning:
const persistedDoc = await xronox.ensureInsert({
dataType: 'metadata',
sourceType: 'database',
subSourceType: 'mongo',
source: 'activities',
mode: 'append',
documents: [{
id: 'activity-123',
status: 'started',
startTime: new Date(),
}],
}, {
keys: ['id'], // Required: keys to use for verification
timeoutMs: 5000, // Default: 5000ms
pollIntervalMs: 100, // Default: 100ms
});
// Returns the persisted document or throws on timeoutensureUpdate()
Update a document and verify the update was applied:
const updatedDoc = await xronox.ensureUpdate({
dataType: 'metadata',
sourceType: 'database',
subSourceType: 'mongo',
source: 'activities',
mode: 'replace',
documents: [{
id: 'activity-123',
status: 'completed',
endTime: new Date(),
}],
}, {
keys: ['id'], // Required: keys to use for verification
timeoutMs: 5000, // Default: 5000ms
pollIntervalMs: 100, // Default: 100ms
strict: true, // Default: true - throw if not found before update
waitForExisting: false, // Default: false - wait for document to appear first
expectedStatus: 'completed', // Optional: verify status field matches
verifyFields: ['endTime'], // Optional: verify these fields exist after update
});
// Returns the updated document or throws on timeout/not-foundOptions
ensureInsert Options:
keys: string[]- Required - Keys to use for polling verificationtimeoutMs?: number- Timeout in milliseconds (default: 5000)pollIntervalMs?: number- Poll interval in milliseconds (default: 100)retry?: { max?, delayMs?, backoff? }- Retry configuration for write operation
ensureUpdate Options:
keys: string[]- Required - Keys to use for polling verificationtimeoutMs?: number- Timeout in milliseconds (default: 5000)pollIntervalMs?: number- Poll interval in milliseconds (default: 100)waitForExisting?: boolean- Wait for document to appear before updating (default: false)expectedStatus?: string- Expected status/field value to verify after updateverifyFields?: string[]- Fields that must exist after updatestrict?: boolean- Throw if document not found before update (default: true)retry?: { max?, delayMs?, backoff? }- Retry configuration for write operation
Use Cases
Activity Tracking Lifecycle:
// Step 1: Insert activity (ensured)
const activity = await xronox.ensureInsert({
source: 'activities',
documents: [{ id: 'act-1', status: 'started' }],
}, { keys: ['id'] });
// Step 2: Update on completion (ensured)
await xronox.ensureUpdate({
source: 'activities',
mode: 'replace',
documents: [{ id: 'act-1', status: 'completed', endTime: new Date() }],
}, {
keys: ['id'],
expectedStatus: 'completed',
verifyFields: ['endTime'],
});Benefits:
- ✅ Deterministic: Either write is visible or clear error is raised
- ✅ Eliminates silent failures: No more "stuck in started" cases
- ✅ Easier debugging: Explicit success/failure
- ✅ Works with queue: Automatically flushes queue before polling
API
See docs/task.md for the complete API specification.
Local Queue (New in 1.10.0)
Xronox now includes a built-in local/in-process queue that automatically handles operations before initialization and batches high-frequency operations for better performance.
Features
- Automatic Queuing: Operations are automatically queued when Xronox is not ready
- Automatic Batching: When ready, rapid
write()calls are automatically batched together - Initialization State API: Check if ready, wait for initialization, listen to events
- Operation Callbacks: Track when operations are queued and completed
- Retry Logic: Automatic retry with exponential backoff for failed operations
- Queue Management: Monitor queue status, manually flush, or clear queue
Basic Usage
The queue is enabled by default - no configuration needed! Operations are automatically queued if Xronox isn't ready yet:
const xronox = createXronox();
// Initialize (async, takes time)
xronox.init({ config, engine: "nxMongo" });
// Operations can be called immediately - will be queued automatically
await xronox.write({
dataType: 'metadata',
sourceType: 'database',
subSourceType: 'mongo',
source: 'my-collection',
mode: 'upsert',
documents: [{ id: '1', name: 'Item 1' }],
keys: ['id'],
});
// Queue is automatically flushed when initialization completesAutomatic Batching
When Xronox is ready, rapid write() calls are automatically batched:
// 100 rapid write() calls
for (let i = 0; i < 100; i++) {
await xronox.write({
dataType: 'metadata',
sourceType: 'database',
subSourceType: 'mongo',
source: 'my-collection',
mode: 'upsert',
documents: [{ id: i, name: `Item ${i}` }],
keys: ['id'],
});
}
// Xronox automatically:
// 1. Queues all 100 operations internally
// 2. Waits 50ms (batchDelay) for more operations
// 3. Batches all operations by (collection, mode, keys)
// 4. Executes single database write with all 100 documents
// 5. Resolves all promises after batch completes
// Result: Much faster than 100 individual writes!Configuration
Customize queue behavior:
await xronox.init({
config,
engine: "nxMongo",
localQueue: {
enabled: true, // Default: true
maxSize: 1000, // Default: 1000
flushOnReady: true, // Default: true - flush when ready
flushInterval: 5000, // Default: 5000ms - periodic flush
batchSize: 100, // Default: 100 - max ops per batch
batchByMode: true, // Default: true - batch by mode separately
autoBatch: true, // Default: true - enable auto-batching
batchDelay: 50, // Default: 50ms - wait time before batching
},
retry: {
enabled: true, // Default: true
maxRetries: 3, // Default: 3
retryDelay: 1000, // Default: 1000ms
exponentialBackoff: true, // Default: true
retryableErrors: [], // Default: [] (all errors)
},
});Initialization State API
Check if Xronox is ready and wait for initialization:
// Check if ready
if (xronox.isReady()) {
// Safe to use
}
// Wait for ready (with optional timeout)
await xronox.waitForReady(5000); // Wait up to 5 seconds
// Get initialization promise
const initPromise = xronox.getInitPromise();
await initPromise;
// Event-based
xronox.on('ready', () => {
console.log('Xronox is ready!');
});
xronox.on('error', (error) => {
console.error('Initialization failed:', error);
});Operation Callbacks
Track operation status with callbacks:
await xronox.write({
// ... write params ...
onQueued: () => {
console.log('Operation queued, will process when ready');
},
onComplete: (result) => {
if (result.success) {
console.log('Operation completed successfully');
} else {
console.error('Operation failed:', result.error);
}
},
});Queue Management
Monitor and manage the queue:
// Get queue status
const status = xronox.getQueueStatus();
console.log(`Queue has ${status.size} operations`);
console.log(`Oldest operation age: ${status.oldestOperationAge}ms`);
// Manually flush queue
await xronox.flushQueue();
// Clear queue (drop all pending operations)
xronox.clearQueue();Queue Behavior
When NOT ready:
- Operations are automatically queued
- Queue is flushed when initialization completes (if
flushOnReady: true) - Periodic flusher runs every
flushIntervalms
When ready + autoBatch === false:
- Operations write immediately (no queue, no batching)
- Traditional behavior
When ready + autoBatch === true:
- Operations are queued for batching (even though ready!)
- Batch delay: wait
batchDelayms (default 50ms) for more operations - Batch size: process when
batchSizereached (default 100) - Batch grouping: by
(collection, mode, keys)tuple - Single database call per batch group
- Promise resolves after batch is written to database
Batch Grouping
Operations are grouped by:
- Collection (
source) - Mode (
insert,upsert,replace,append) - Keys (for upsert operations - same keys = same batch)
Operations with the same grouping key are batched together. Different modes or keys create separate batches.
Disable Queue
To disable the queue (operations will throw errors if not ready):
await xronox.init({
config,
engine: "nxMongo",
localQueue: {
enabled: false, // Disable queue
},
});Configuration
Automatic Config Resolution: xronox automatically resolves ENV placeholders in your config using @x12i/env (enabled by default). You can pass config with ENV.VAR_NAME or ENV.VAR_NAME||default placeholders, and xronox will resolve them automatically.
Automatic .env File Loading: xronox automatically loads .env files using @x12i/env (enabled by default). Environment variables from .env files are available for config resolution.
No direct dependency: You don't need to call @x12i/env directly—xronox handles it internally.
Logging (errors-only by default)
xronox uses @x12i/logxer for package-level logs (env prefix XRONOX). To avoid noisy output for downstream users, xronox is errors-only by default.
To enable richer local logs (debug/info/warn), explicitly opt in:
ENABLE_XRONOX_LOGXER=true
XRONOX_LOGS_LEVEL=debugNotes:
- If
ENABLE_XRONOX_LOGXERis unset/false, xronox suppressesdebug/info/warnregardless ofXRONOX_LOGS_LEVEL. - Use
XRONOX_LOGS_LEVEL=offto silence all logs (including errors).
Lazy Initialization (New in 1.4.0)
xronox now supports lazy initialization - operations will auto-initialize on first use if not already initialized. This makes it easier to use xronox without explicit init() calls:
const xronox = createXronox();
// Store init options (lazy init enabled by default)
xronox.init({
config,
engine: "nxMongo",
lazyInit: true // default: true
});
// Operations will auto-initialize if needed
const results = await xronox.read({ /* ... */ }); // Auto-inits on first callDisable lazy init if you want explicit initialization:
await xronox.init({
config,
engine: "nxMongo",
lazyInit: false // Require explicit init
});Config Auto-Discovery (New in 1.4.0)
xronox can automatically discover config from common locations:
const xronox = createXronox();
// Enable auto-discovery - will search for:
// - xronox.config.json
// - .xronoxrc
// - .xronoxrc.json
// - config/xronox.json
// - config/xronox.config.json
await xronox.init({
autoDiscoverConfig: true,
engine: "nxMongo" // Still required
});Zero-Config Mode (New in 1.4.0) ⚡
xronox can now work with zero configuration - just add MONGO_URI to your .env file and you're done!
// .env file
MONGO_URI=mongodb://localhost:27017
MONGO_DB=myapp// That's it! No config needed
const xronox = createXronox();
// Zero-config mode - automatically creates minimal config from .env
await xronox.init({
engine: "nxMongo",
zeroConfig: true // Automatically enabled if no config provided
});
// Or even simpler - just use it, zero-config happens automatically
const xronox = createXronox();
xronox.init({ engine: "nxMongo" }); // No config needed!
// Start using it immediately
const results = await xronox.read({
dataType: "metadata",
sourceType: "database",
subSourceType: "mongo",
source: "my-collection",
query: {}
});How it works:
- xronox automatically loads
.envfile - Extracts
MONGO_URI(orMONGO_URL,XRONOX_MONGO_URI) - Extracts
MONGO_DB(orMONGO_KNOWLEDGE_DB,XRONOX_MONGO_DB) - takes priority over database name in URI (fixed in 1.7.2) - Creates minimal config automatically
- Initializes and works!
Environment variables supported:
MONGO_URIorMONGO_URLorXRONOX_MONGO_URI- MongoDB connection stringMONGO_DBorMONGO_KNOWLEDGE_DBorXRONOX_MONGO_DB- Database name (defaults tocoreif not found)MONGO_ALIASorXRONOX_MONGO_ALIAS- Connection alias (defaults tomongo-primary)MONGO_ROLEorXRONOX_MONGO_ROLE- Database role for automatic resolution (NEW in 2.2.0)
Important: The MONGO_DB environment variable now takes priority over any database name specified in the connection URI. This allows you to override the database name in the URI, which is useful when the URI contains a different database name (e.g., authentication database) than the one you want to use for operations.
Role-Based Configuration (New in 2.2.0) 🎯
xronox now supports role-based database configuration using @x12i/env OOTB presets. Instead of hardcoding connection strings and database names, you can specify a role and let xronox automatically resolve them from your .env file.
How It Works
Role-based configuration uses a normalized preset structure to automatically resolve:
- Connection URI from
config.database.mongodb.roles.<role>.uri - Database name from
config.database.mongodb.roles.<role>.database
Benefits:
- ✅ No hardcoded connection strings - managed through
.envfiles - ✅ Automatic resolution - from
.envvia@x12i/envpresets - ✅ Empty string handling - empty
uri/dbvalues fall back to.envresolution - ✅ Multi-database support - easily manage multiple databases per role
- ✅ Backward compatible - explicit
uri/dbstill work and take precedence
Basic Usage
// .env file
MONGO_URI=mongodb://localhost:27017
MONGO_AI_LOGS_DB=ai-logs
MONGO_LOGS_DB=logs
MONGO_OPERATIONAL_DB=operational
// Config - uri and db are now OPTIONAL when role is provided
const config: XronoxConfig = {
connections: {
database: {
mongo: [
{
alias: 'ai-logs',
role: 'ai_logs' // ✅ No uri/db needed - resolved from .env
},
{
alias: 'logs',
role: 'logs' // ✅ Resolves MONGO_URI + MONGO_LOGS_DB
},
{
alias: 'operational',
role: 'operational' // ✅ Resolves MONGO_URI + MONGO_OPERATIONAL_DB
}
]
}
},
bindings: [
{
subSourceType: 'mongo',
connection: 'ai-logs',
defaults: {
role: 'ai_logs' // ✅ Role for default operations
}
}
]
};Supported Roles
xronox supports the following roles with automatic fallback chains:
Logs Roles:
ai_logs→ falls back tologs→ falls back tooperationallogs→ falls back tooperational
Operational Roles:
operational(central, usesMONGO_DB)runtime→ falls back tooperationalproviders→ falls back tooperational
Memory Roles:
memory→ falls back tooperationalshortTermMemory→ falls back tomemory→operationallongTermMemory→ falls back tomemory→operationalworkExperience→ falls back tomemory→operationalworkLessons→ falls back tomemory→operational
Domain Knowledge Roles:
domainKnowledge→ falls back tooperationaldomain-knowledge→ falls back todomainKnowledge→operationaldomainKnowHows→ falls back todomainKnowledge→operationaldomainNarratives→ falls back todomainKnowledge→operationaldomainProKnowledge→ falls back todomainKnowledge→operational
Mapping / XMemory Roles (used by @xronoces/xmemory-records-mapper and by xmemory-equal / xmemory-relations when used with xronox as the data tier):
mapping_source→ DB to map from (read-only source). Resolves fromroles.mapping_sourcethen base only; no fallback to operational (required when using the mapper).mapping_metadata→ XMemory metadata DB (schema Things, collection/schema-relation edges). Falls back tomapping_operationalthen base then operational.mapping_operational→ XMemory operational DB (record Things, record-relation edges). Falls back to base then operational.mapping→ Single DB for both metadata and operational (one-DB xmemory mode). Falls back to base then operational.
Unknown/Empty Role: Falls back to operational
Environment Variables
OOTB presets support role-specific environment variables:
# Base connection (shared by default)
MONGO_URI=mongodb://localhost:27017
MONGO_DB=app
# Role-specific overrides
MONGO_LOGS_URI=mongodb://logs:27017 # Optional - overrides base URI for logs role
MONGO_LOGS_DB=logs # Optional - overrides base DB for logs role
MONGO_AI_LOGS_URI=mongodb://ai-logs:27017 # Optional - sub-role override
MONGO_AI_LOGS_DB=ai-logs # Optional - sub-role override
MONGO_MEMORY_URI=mongodb://memory:27017
MONGO_MEMORY_DB=memory
MONGO_OPERATIONAL_DB=operational
# Mapping / XMemory (for xmemory-records-mapper and xmemory-equal / xmemory-relations)
MONGO_MAPPING_SOURCE_DB=source # DB to map from (uses MONGO_URI; required when using mapper)
MONGO_MAPPING_METADATA_DB=xmemory-meta # Optional - falls back to MONGO_MAPPING_OPERATIONAL_DB
MONGO_MAPPING_OPERATIONAL_DB=xmemory-op # Optional - falls back to MONGO_OPERATIONAL_DB
MONGO_MAPPING_DB=xmemory # Optional - single DB for both metadata and operationalEmpty String Handling
If uri or db is provided but empty, xronox automatically falls back to .env resolution:
{
alias: 'ai-logs',
uri: '', // ✅ Empty - will fall back to .env via role
db: '', // ✅ Empty - will fall back to .env via role
role: 'ai_logs'
}
// Result: Uses MONGO_URI and MONGO_AI_LOGS_DB from .envPriority Resolution
Connection string and database name resolution follows this priority:
- Explicit
uri/db(if provided and non-empty) - highest priority - Role-based resolution (if
roleprovided) - uses normalized preset structure - Alias inference (if no role, tries to infer from alias)
- Default to 'operational' (if nothing else works)
Zero-Config with Roles
You can use role-based configuration in zero-config mode:
// .env file
MONGO_URI=mongodb://localhost:27017
MONGO_ROLE=ai_logs
MONGO_AI_LOGS_DB=ai-logs
// Code
await xronox.init({
engine: 'nxMongo',
zeroConfig: true // ✅ Automatically creates role-based config from .env
});Backward Compatibility
Explicit uri and db values still work and take precedence:
{
alias: 'primary',
uri: 'mongodb://custom-host:27017', // ✅ Takes precedence over role
db: 'custom-db', // ✅ Takes precedence over role
role: 'ai_logs' // Used only if uri/db are missing or empty
}Alias Inference
If no role is provided, xronox tries to infer it from the alias:
{
alias: 'ai-logs-connection', // Contains 'ai' and 'logs'
// No role specified - will infer 'ai_logs' from alias
}
// Inferred roles:
// - 'ai-logs', 'ai_logs' → 'ai_logs'
// - 'logs', 'logging' → 'logs'
// - 'memory', 'mem' → 'memory'
// - 'operational', 'runtime' → 'operational'
// - Unknown → 'operational' (default)Operation-Level Role Parameter (New in 2.5.0) 🆕
You can now pass role as an optional parameter to any read/write operation to override the binding's default database for that specific operation:
// Config with default binding
const config: XronoxConfig = {
connections: {
database: {
mongo: [{
alias: 'mongo-primary',
uri: 'mongodb://localhost:27017',
role: 'operational'
}]
}
},
bindings: [{
subSourceType: 'mongo',
connection: 'mongo-primary',
defaults: { db: 'operational-db' } // Default database
}]
};
// Use default database (from binding)
await xronox.read({
dataType: 'metadata',
sourceType: 'database',
subSourceType: 'mongo',
source: 'users'
// Uses 'operational-db' from binding defaults
});
// Override with role parameter - uses AI logs database instead
await xronox.read({
dataType: 'metadata',
sourceType: 'database',
subSourceType: 'mongo',
source: 'users',
role: 'ai_logs' // ✅ Overrides binding default, uses AI logs database
});
// Works for all operations
await xronox.write({
dataType: 'operation',
sourceType: 'database',
subSourceType: 'mongo',
source: 'operations',
documents: [...],
role: 'logs' // ✅ Uses logs database instead of binding default
});
await xronox.readOne({
dataType: 'knowledge',
sourceType: 'database',
subSourceType: 'mongo',
source: 'articles',
filter: { id: '123' },
role: 'domainKnowledge' // ✅ Uses domain knowledge database
});Priority Order:
roleparameter (if provided in operation) - highest priority- Binding defaults (if no role parameter) - fallback
Benefits:
- ✅ Flexible database selection - choose database per operation without changing bindings
- ✅ Override defaults - use different databases for different operations on the same collection
- ✅ Backward compatible - if
roleis not provided, uses binding defaults (existing behavior) - ✅ Type-safe - TypeScript knows
roleis an optional parameter on all operations
When to Use:
- When you need to read/write to different databases for the same collection
- When you want to override the binding's default database for specific operations
- When working with multi-tenant applications where different operations need different databases
Minimal Config Mode (New in 1.4.0)
xronox now supports minimal configurations - you can work with just MongoDB, no storage required:
// Minimal config - MongoDB only, no storage
const minimalConfig: XronoxConfig = {
connections: {
database: {
mongo: [
{
alias: "mongo-primary",
uri: "ENV.MONGO_URI||mongodb://localhost:27017",
db: "ENV.MONGO_DB||core"
}
]
}
// No storage connections needed!
},
bindings: [
{
subSourceType: "mongo",
connection: "mongo-primary",
defaults: { db: "ENV.MONGO_DB||core" }
}
]
};Storage is optional - xronox will work fine with just database connections. Storage connections are only needed if you use readObject() or writeObject().
.env File Options
// Use default .env file (in current directory)
await xronox.init({
config,
engine: "nxMongo"
// envFile defaults to loading .env if it exists
});
// Specify custom .env file path
await xronox.init({
config,
engine: "nxMongo",
envFile: ".env.local" // Load specific .env file
});
// Load multiple .env files (loaded in order)
await xronox.init({
config,
engine: "nxMongo",
envFile: [".env", ".env.local", ".env.production"] // Later files override earlier ones
});
// Disable .env file loading
await xronox.init({
config,
engine: "nxMongo",
envFile: false // Skip .env file loading entirely
});Disable Auto-Resolution
If you prefer to resolve config yourself, set autoResolveConfig: false:
await xronox.init({
config: preResolvedConfig, // Already resolved by your code
engine: "nxMongo",
autoResolveConfig: false // Disable automatic resolution
});See docs/task.md for complete configuration schema.
SSL/TLS Configuration (New in 1.7.1)
xronox supports full SSL/TLS configuration for MongoDB connections through the options object in your connection configuration. This is essential for production deployments connecting to MongoDB Atlas or self-hosted MongoDB instances with SSL/TLS enabled.
Basic SSL/TLS Configuration
const config: XronoxConfig = {
connections: {
database: {
mongo: [
{
alias: "mongo-primary",
uri: "mongodb://host:27017",
db: "mydb",
options: {
// Enable SSL/TLS
ssl: true,
// Validate SSL certificates (recommended for production)
sslValidate: true,
// Allow invalid certificates (only for testing/development)
// sslAllowInvalidCertificates: false,
}
}
]
}
},
bindings: [
{ subSourceType: "mongo", connection: "mongo-primary" }
]
};MongoDB Atlas Connection
MongoDB Atlas requires SSL/TLS by default. The connection string typically includes SSL parameters, but you can also configure them explicitly:
const config: XronoxConfig = {
connections: {
database: {
mongo: [
{
alias: "atlas-primary",
uri: "mongodb+srv://user:[email protected]/",
db: "mydb",
options: {
// MongoDB Atlas uses TLS by default, but explicit config is recommended
tls: true,
tlsAllowInvalidCertificates: false, // Always false for production
// Connection pool settings
maxPoolSize: 10,
minPoolSize: 2,
serverSelectionTimeoutMS: 5000,
}
}
]
}
},
bindings: [
{ subSourceType: "mongo", connection: "atlas-primary" }
]
};Self-Signed Certificates
For self-hosted MongoDB with self-signed certificates:
const config: XronoxConfig = {
connections: {
database: {
mongo: [
{
alias: "self-signed-mongo",
uri: "mongodb://host:27017",
db: "mydb",
options: {
ssl: true,
sslValidate: true,
// Path to CA certificate file (absolute path recommended)
sslCA: "/path/to/ca-certificate.pem",
// For testing only - allows invalid certificates
// sslAllowInvalidCertificates: true,
}
}
]
}
},
bindings: [
{ subSourceType: "mongo", connection: "self-signed-mongo" }
]
};Client Certificate Authentication
For MongoDB instances requiring client certificate authentication:
const config: XronoxConfig = {
connections: {
database: {
mongo: [
{
alias: "client-cert-mongo",
uri: "mongodb://host:27017",
db: "mydb",
options: {
ssl: true,
sslValidate: true,
// CA certificate
sslCA: "/path/to/ca-certificate.pem",
// Client certificate
sslCert: "/path/to/client-certificate.pem",
// Client private key
sslKey: "/path/to/client-private-key.pem",
// Optional: Passphrase for private key
sslPass: "your-passphrase",
}
}
]
}
},
bindings: [
{ subSourceType: "mongo", connection: "client-cert-mongo" }
]
};Modern TLS Options (Recommended)
The MongoDB Node.js driver supports both legacy (ssl*) and modern (tls*) option names. Modern names are preferred:
const config: XronoxConfig = {
connections: {
database: {
mongo: [
{
alias: "modern-tls-mongo",
uri: "mongodb://host:27017",
db: "mydb",
options: {
// Modern TLS options (preferred)
tls: true,
tlsAllowInvalidCertificates: false,
tlsAllowInvalidHostnames: false,
tlsCAFile: "/path/to/ca-certificate.pem",
tlsCertificateKeyFile: "/path/to/client-cert-and-key.pem",
tlsCertificateKeyFilePassword: "your-passphrase",
// Or separate certificate and key files
// tlsCertificateFile: "/path/to/client-certificate.pem",
// tlsPrivateKeyFile: "/path/to/client-private-key.pem",
}
}
]
}
},
bindings: [
{ subSourceType: "mongo", connection: "modern-tls-mongo" }
]
};Local Development (No SSL)
For local MongoDB without SSL, no special configuration is needed:
const config: XronoxConfig = {
connections: {
database: {
mongo: [
{
alias: "local-mongo",
uri: "mongodb://localhost:27017",
db: "mydb",
// No options needed - SSL is disabled by default
}
]
}
},
bindings: [
{ subSourceType: "mongo", connection: "local-mongo" }
]
};Supported SSL/TLS Options
xronox supports all standard MongoDB Node.js driver SSL/TLS options:
Legacy SSL Options:
ssl: boolean- Enable/disable SSLsslValidate: boolean- Validate SSL certificatessslCA: string- Path to CA certificate filesslCert: string- Path to client certificate filesslKey: string- Path to client private key filesslPass: string- Passphrase for private keysslCRL: string- Path to Certificate Revocation ListsslAllowInvalidCertificates: boolean- Allow invalid certificates (testing only)
Modern TLS Options (Preferred):
tls: boolean- Enable/disable TLStlsInsecure: boolean- Disable certificate validation (testing only)tlsAllowInvalidCertificates: boolean- Allow invalid certificates (testing only)tlsAllowInvalidHostnames: boolean- Allow invalid hostnames (testing only)tlsCAFile: string- Path to CA certificate filetlsCertificateKeyFile: string- Path to combined certificate and key filetlsCertificateKeyFilePassword: string- Passphrase for certificate key filetlsCertificateFile: string- Path to client certificate filetlsPrivateKeyFile: string- Path to client private key file
Other Connection Options:
maxPoolSize: number- Maximum connection pool sizeminPoolSize: number- Minimum connection pool sizeconnectTimeoutMS: number- Connection timeout in millisecondssocketTimeoutMS: number- Socket timeout in millisecondsserverSelectionTimeoutMS: number- Server selection timeout in millisecondsauthSource: string- Authentication databaseauthMechanism: string- Authentication mechanismretryWrites: boolean- Enable retryable writesretryReads: boolean- Enable retryable reads
Using Environment Variables
You can use environment variables for SSL certificate paths:
const config: XronoxConfig = {
connections: {
database: {
mongo: [
{
alias: "mongo-primary",
uri: "ENV.MONGO_URI||mongodb://localhost:27017",
db: "ENV.MONGO_DB||mydb",
options: {
ssl: true,
sslValidate: true,
sslCA: "ENV.MONGO_CA_CERT||/path/to/ca-cert.pem",
sslCert: "ENV.MONGO_CLIENT_CERT||/path/to/client-cert.pem",
sslKey: "ENV.MONGO_CLIENT_KEY||/path/to/client-key.pem",
}
}
]
}
},
bindings: [
{ subSourceType: "mongo", connection: "mongo-primary" }
]
};Important Notes
File Paths: Certificate file paths should be absolute paths. Relative paths may not work correctly depending on the working directory.
Option Passthrough: All options in the
optionsobject are passed through to the MongoDB driver. xronox merges these options into the connection URI to ensure compatibility.URI vs Options: You can specify SSL options either in the connection URI (as query parameters) or in the
optionsobject. Theoptionsobject provides more explicit control and is recommended.Testing: For testing with self-signed certificates, you can use
sslAllowInvalidCertificates: trueortlsAllowInvalidCertificates: true. Never use this in production.MongoDB Atlas: MongoDB Atlas connections typically use
mongodb+srv://URIs which include SSL/TLS by default. Explicit TLS options are still recommended for clarity.Certificate Formats: MongoDB driver supports PEM format certificates. Ensure your certificate files are in the correct format.
For more details, see:
- SSL/TLS Configuration Guide - Comprehensive guide with examples and troubleshooting
- MongoDB Node.js Driver TLS/SSL documentation
Troubleshooting
Self-Test: Check Your Setup
Use selfTest() to validate your xronox configuration and detect missing components:
const xronox = createXronox();
await xronox.init({ config, engine: "nxMongo" });
// Run self-test (configuration checks only)
const result = await xronox.selfTest?.();
console.log(result.passed ? '✅ All checks passed' : '❌ Issues found');
result.checks.forEach(check => {
console.log(`${check.status === 'pass' ? '✅' : '❌'} ${check.name}: ${check.message}`);
});
// Run self-test with connectivity checks (tests actual connections)
const resultWithConnectivity = await xronox.selfTest?.({ testConnectivity: true });Self-test checks:
- ✅ Initialization status
- ✅ Configuration presence
- ✅ Connections configuration
- ✅ MongoDB connections validity
- ✅ Bindings configuration
- ✅ Binding-connection consistency
- ✅ Engine mode and instance
- ✅ Environment variables (if using ENV placeholders)
- ✅ MongoDB connectivity (if
testConnectivity: true)
Enhanced Troubleshooting (New in 1.4.0)
xronox now includes smarter error detection and troubleshooting:
- Fallback chain analysis - Detects when environment variables use fallback chains (e.g.,
ENV.XRONOX_MONGO_URI||ENV.MONGO_URI||default) and reports which variables are actually resolved - Config validation - Validates minimal config requirements before initialization
- Better error messages - More helpful error messages that explain what's missing and how to fix it
Example: If you see "Missing variables: XRONOX_MONGO_URI" but your config uses ENV.XRONOX_MONGO_URI||ENV.MONGO_URI||default, xronox will detect that MONGO_URI is set and explain that the error message can be misleading. The selfTest() method will show which variables are using fallbacks.
Having issues? Run the comprehensive tester to get detailed bug reports with troubleshooting suggestions:
npm run test:comprehensiveSee the Troubleshooting Guide for:
- How to use the comprehensive tester
- Understanding bug reports
- Common issues and solutions
- Adding custom troubleshooting narratives
- Integration with CI/CD
Support Matrix
See docs/support-matrix.md for detailed capabilities and limitations of each engine.
Upstream Fix Requests
See docs/upstream-fixes.md for small, optional improvements requested from upstream packages.
Xontext Feature Requests
See docs/xontext-feature-requests.md for feature requests to better support the Xontext architecture, including queue management, pub/sub messaging, caching, distributed locks, vector search, and more.
xronox-core Change Request
See docs/xronox-core-change-request.md for the feature specification that led to lazy collection creation and natural head collection UX in xronox-core 2.4.0+.
Development
Building
npm run buildTesting & Troubleshooting
Quick Start: Run Comprehensive Tests
The easiest way to test xronox and catch common issues is to run the comprehensive tester:
npm run test:comprehensiveThis will:
- ✅ Test 30+ failure scenarios across both engines
- ✅ Automatically generate bug reports with troubleshooting suggestions
- ✅ Match errors to troubleshooting narratives from
metadata/troubleshooting.json - ✅ Provide step-by-step solutions for common issues
Setup: Create tests/config.json with your MongoDB connection:
{
"MONGO_URL": "mongodb://user:pass@host:port/db?authSource=admin"
}See Troubleshooting Guide for detailed instructions, understanding bug reports, and advanced usage.
Basic Tests
Basic tests are located in the tests/ directory:
- Create
tests/config.jsonwith your MongoDB connection string - Run:
npx ts-node tests/basic.test.ts
Comprehensive Tester Details
The comprehensive tester (tests/xronox-comprehensive-tester.ts) covers:
- Configuration errors: Missing fields, invalid structure, binding issues
- Initialization errors: Double init, invalid engine, connection failures
- Query errors: Invalid parameters, malformed filters, type mismatches
- Write errors: Missing documents, invalid modes, validation failures
- Environment issues: Variable resolution, .env file loading
- Tenancy errors: Binding matching, routing failures
- Lifecycle errors: Operations after close, double close
Bug Reports: When errors occur, detailed reports are saved to .bug-reports/ with:
- Complete error details and stack traces
- Configuration snapshots
- Query details and evidence
- Troubleshooting suggestions matched from
metadata/troubleshooting.json
Troubleshooting Narratives: The tester automatically matches errors to 29+ predefined troubleshooting scenarios in metadata/troubleshooting.json, providing contextual solutions for common issues.
Note: The tests/ directory and tests/config.json are excluded from git for security.
ERC 2.0 Compliance
@xronoces/xronox is ERC 2.0 compliant, following the Env-Ready Component Standard 2.0.
Features
- ✅ Zero-Config Initialization: Auto-discovers configuration from environment variables
- ✅ Automatic Documentation: Generates
erc-manifest.jsonand.env.exampleautomatically - ✅ Type Safety: Built-in type coercion and validation via
@x12i/env - ✅ Transitive Requirements: Automatically merges dependency requirements
- ✅ Compliance Verification: Built-in CLI verification tool
Enabling ERC 2.0 Mode
Enable ERC 2.0 compliance by setting erc.enabled: true in your initialization options:
import { createXronox } from '@xronoces/xronox';
const xronox = createXronox();
await xronox.init({
engine: 'nxMongo',
config: {
connections: {
database: {
mongo: [{
alias: 'mongo-primary',
uri: 'ENV.MONGO_URI',
db: 'ENV.MONGO_DB||core'
}]
}
},
bindings: [{
subSourceType: 'mongo',
connection: 'mongo-primary',
defaults: { db: 'ENV.MONGO_DB||core' }
}]
},
erc: {
enabled: true,
generateManifest: true, // Generate erc-manifest.json
generateEnvExample: true, // Generate .env.example
throwOnMissing: true, // Throw error on missing required variables
dependencies: [], // List ERC-compliant dependencies
descriptions: { // Custom variable descriptions
MONGO_URI: 'MongoDB connection string',
MONGO_DB: 'Default database name'
}
}
});Environment Variables
When ERC 2.0 mode is enabled, xronox automatically:
- Discovers environment variables from
process.env - Validates required variables are present
- Generates
erc-manifest.jsonwith all requirements - Generates
.env.examplewith transitive dependencies
Common Environment Variables:
MONGO_URI/MONGO_URL/XRONOX_MONGO_URI- MongoDB connection stringMONGO_DB/MONGO_KNOWLEDGE_DB/XRONOX_MONGO_DB- Database nameMONGO_ALIAS/XRONOX_MONGO_ALIAS- Connection aliasMONGO_ROLE/XRONOX_MONGO_ROLE- Database role for automatic resolutionAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY- S3 storage credentials (if using S3)
Verification
Verify ERC 2.0 compliance:
# Verify compliance
npm run erc:verify
# Or use directly
npm run erc:verifyAdvanced Mode (Programmatic Configuration)
ERC 2.0 supports both zero-config and explicit configuration:
// Zero-config: Auto-discovers from process.env
await xronox.init({
engine: 'nxMongo',
erc: { enabled: true }
});
// Advanced mode: Explicit configuration (bypasses auto-discovery)
await xronox.init({
engine: 'nxMongo',
config: {
connections: {
database: {
mongo: [{
alias: 'mongo-primary',
uri: 'mongodb://localhost:27017',
db: 'myapp'
}]
}
},
bindings: [{
subSourceType: 'mongo',
connection: 'mongo-primary'
}]
},
erc: { enabled: true } // Still generates manifest/docs
});Dependencies
All ERC 2.0-compliant dependencies are automatically validated. If a dependency is not ERC 2.0-compliant, initialization will fail with a descriptive error.
ERC-Compliant Dependencies:
- ✅
@x12i/env(Configuration engine) - ✅
@xronoces/xronox-core(if using xronoxCore engine) - ✅
@xronoces/xronox-router(Routing support)
For more information, see the ERC 2.0 Standard Documentation.
License
ISC
