npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@x12i/xronox

v3.7.3

Published

Data-tier adapter support

Readme

@xronoces/xronox

Version: 3.0.0

ERC 2.0 Compliant

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:verify

See 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-scoping

This tests all content scoping features with real MongoDB and S3 operations.

Installation

npm install @xronoces/xronox

Features

  • Unified API for database and storage operations
  • Two engine modes: nxMongo (direct MongoDB) and xronoxCore (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 .env files 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-troubleshooting for 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, objectExists now 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/ensureUpdate with pluggable backends (memory/persistent/redis)
  • 🆕 Role-based configuration (v2.2.0) - Automatic connection string and database name resolution from roles using @x12i/env OOTB presets. No need to hardcode uri/db - specify a role and let xronox resolve from .env
  • 🆕 Operation-level role parameter (v2.5.0) - Pass role as 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=myapp
import { 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-localfs

Example 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 *-head collections 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 timeout

ensureUpdate()

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-found

Options

ensureInsert Options:

  • keys: string[] - Required - Keys to use for polling verification
  • timeoutMs?: 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 verification
  • timeoutMs?: 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 update
  • verifyFields?: string[] - Fields that must exist after update
  • strict?: 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 completes

Automatic 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 flushInterval ms

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 batchDelay ms (default 50ms) for more operations
  • Batch size: process when batchSize reached (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=debug

Notes:

  • If ENABLE_XRONOX_LOGXER is unset/false, xronox suppresses debug/info/warn regardless of XRONOX_LOGS_LEVEL.
  • Use XRONOX_LOGS_LEVEL=off to 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 call

Disable 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:

  1. xronox automatically loads .env file
  2. Extracts MONGO_URI (or MONGO_URL, XRONOX_MONGO_URI)
  3. Extracts MONGO_DB (or MONGO_KNOWLEDGE_DB, XRONOX_MONGO_DB) - takes priority over database name in URI (fixed in 1.7.2)
  4. Creates minimal config automatically
  5. Initializes and works!

Environment variables supported:

  • MONGO_URI or MONGO_URL or XRONOX_MONGO_URI - MongoDB connection string
  • MONGO_DB or MONGO_KNOWLEDGE_DB or XRONOX_MONGO_DB - Database name (defaults to core if not found)
  • MONGO_ALIAS or XRONOX_MONGO_ALIAS - Connection alias (defaults to mongo-primary)
  • MONGO_ROLE or XRONOX_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 .env files
  • Automatic resolution - from .env via @x12i/env presets
  • Empty string handling - empty uri/db values fall back to .env resolution
  • Multi-database support - easily manage multiple databases per role
  • Backward compatible - explicit uri/db still 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 to logs → falls back to operational
  • logs → falls back to operational

Operational Roles:

  • operational (central, uses MONGO_DB)
  • runtime → falls back to operational
  • providers → falls back to operational

Memory Roles:

  • memory → falls back to operational
  • shortTermMemory → falls back to memoryoperational
  • longTermMemory → falls back to memoryoperational
  • workExperience → falls back to memoryoperational
  • workLessons → falls back to memoryoperational

Domain Knowledge Roles:

  • domainKnowledge → falls back to operational
  • domain-knowledge → falls back to domainKnowledgeoperational
  • domainKnowHows → falls back to domainKnowledgeoperational
  • domainNarratives → falls back to domainKnowledgeoperational
  • domainProKnowledge → falls back to domainKnowledgeoperational

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 from roles.mapping_source then base only; no fallback to operational (required when using the mapper).
  • mapping_metadata → XMemory metadata DB (schema Things, collection/schema-relation edges). Falls back to mapping_operational then 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 operational

Empty 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 .env

Priority Resolution

Connection string and database name resolution follows this priority:

  1. Explicit uri/db (if provided and non-empty) - highest priority
  2. Role-based resolution (if role provided) - uses normalized preset structure
  3. Alias inference (if no role, tries to infer from alias)
  4. 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:

  1. role parameter (if provided in operation) - highest priority
  2. 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 role is not provided, uses binding defaults (existing behavior)
  • Type-safe - TypeScript knows role is 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 SSL
  • sslValidate: boolean - Validate SSL certificates
  • sslCA: string - Path to CA certificate file
  • sslCert: string - Path to client certificate file
  • sslKey: string - Path to client private key file
  • sslPass: string - Passphrase for private key
  • sslCRL: string - Path to Certificate Revocation List
  • sslAllowInvalidCertificates: boolean - Allow invalid certificates (testing only)

Modern TLS Options (Preferred):

  • tls: boolean - Enable/disable TLS
  • tlsInsecure: 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 file
  • tlsCertificateKeyFile: string - Path to combined certificate and key file
  • tlsCertificateKeyFilePassword: string - Passphrase for certificate key file
  • tlsCertificateFile: string - Path to client certificate file
  • tlsPrivateKeyFile: string - Path to client private key file

Other Connection Options:

  • maxPoolSize: number - Maximum connection pool size
  • minPoolSize: number - Minimum connection pool size
  • connectTimeoutMS: number - Connection timeout in milliseconds
  • socketTimeoutMS: number - Socket timeout in milliseconds
  • serverSelectionTimeoutMS: number - Server selection timeout in milliseconds
  • authSource: string - Authentication database
  • authMechanism: string - Authentication mechanism
  • retryWrites: boolean - Enable retryable writes
  • retryReads: 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

  1. File Paths: Certificate file paths should be absolute paths. Relative paths may not work correctly depending on the working directory.

  2. Option Passthrough: All options in the options object are passed through to the MongoDB driver. xronox merges these options into the connection URI to ensure compatibility.

  3. URI vs Options: You can specify SSL options either in the connection URI (as query parameters) or in the options object. The options object provides more explicit control and is recommended.

  4. Testing: For testing with self-signed certificates, you can use sslAllowInvalidCertificates: true or tlsAllowInvalidCertificates: true. Never use this in production.

  5. MongoDB Atlas: MongoDB Atlas connections typically use mongodb+srv:// URIs which include SSL/TLS by default. Explicit TLS options are still recommended for clarity.

  6. Certificate Formats: MongoDB driver supports PEM format certificates. Ensure your certificate files are in the correct format.

For more details, see:

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:comprehensive

See 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 build

Testing & 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:comprehensive

This 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:

  1. Create tests/config.json with your MongoDB connection string
  2. 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.json and .env.example automatically
  • 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:

  1. Discovers environment variables from process.env
  2. Validates required variables are present
  3. Generates erc-manifest.json with all requirements
  4. Generates .env.example with transitive dependencies

Common Environment Variables:

  • MONGO_URI / MONGO_URL / XRONOX_MONGO_URI - MongoDB connection string
  • MONGO_DB / MONGO_KNOWLEDGE_DB / XRONOX_MONGO_DB - Database name
  • MONGO_ALIAS / XRONOX_MONGO_ALIAS - Connection alias
  • MONGO_ROLE / XRONOX_MONGO_ROLE - Database role for automatic resolution
  • AWS_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:verify

Advanced 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