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

v2.7.3

Published

Core operations for Xronox including CRUD, versioning, transactions, and entity relationships with Poiesis Foundation Rules 25, 26, 27 compliance

Readme

@x12i/xronox-core

Version: 2.5.0
Status: Active
Expertise: Core CRUD operations with storage externalization

🚀 Env-Ready Component (ERC 2.0)

This component supports zero-config initialization via environment variables using @x12i/env. ERC 2.0 compliant with automatic manifest generation and transitive dependency documentation.

Core database operations for the Xronox ecosystem, providing unified CRUD operations with storage externalization, versioning support, and comprehensive audit trails.

Why This Package Exists

The Xronox ecosystem needed a unified, robust database operations layer that could handle complex data management requirements with storage externalization for large binary data.

Before this package:

  • Each application implemented CRUD operations separately
  • No standardized storage externalization
  • Inconsistent error handling and validation
  • No unified approach to versioning and audit trails

Now:

  • Single, expert CRUD implementation used by all Xronox applications
  • Automatic storage externalization for base64/binary data
  • Consistent error handling with detailed context
  • Built-in versioning and audit trails
  • Config-driven transaction support
  • Lazy collection creation - Collections created automatically on first write
  • Natural head collection UX - Work with *-head collections like normal MongoDB collections

Installation

npm install @x12i/xronox-core

Peer Dependencies

npm install @x12i/xronox-router @x12i/xronox-storage-interface

Quick Start (Zero-Config Mode)

xronox-core supports zero-config initialization via environment variables:

# 1. Install the package
npm install @x12i/xronox-core

# 2. Copy .env.example to .env (auto-generated in node_modules/@x12i/xronox-core/)
cp node_modules/@x12i/xronox-core/.env.example .env

# 3. Fill in required values in .env
# MONGO_URI=mongodb://localhost:27017
# MONGO_DB=xronox_demo
# SPACE_ENDPOINT=https://s3.amazonaws.com
# SPACE_BUCKET=my-bucket
# SPACE_ACCESS_KEY=your-key
# SPACE_SECRET_KEY=your-secret

# 4. Use with zero config!
import { createSingleXronox } from '@x12i/xronox-core';
const router = createSingleXronox(); // Auto-discovers from process.env

Configuration Modes

xronox-core auto-detects the configuration mode:

Simple Mode (Zero-Config):

  • No xronox.config.json file exists
  • Uses essential environment variables only
  • Perfect for simple deployments

Complex Mode (Advanced):

  • xronox.config.json file exists in project root
  • Supports full configuration with routing, multi-tenant, collection maps, etc.
  • Still generates ERC manifest for documentation

Both modes are ERC 2.0 compliant and generate erc-manifest.json and .env.example automatically.

Environment Variables

See .env.example for the complete list of required and optional variables with descriptions.

Essential Variables (Simple Mode):

  • MONGO_URI - MongoDB connection URI (required)
  • MONGO_DB - Logical database name (default: xronox_demo)
  • SPACE_ENDPOINT - S3-compatible storage endpoint (required)
  • SPACE_BUCKET - Storage bucket name (required)
  • SPACE_ACCESS_KEY - Storage access key (required)
  • SPACE_SECRET_KEY - Storage secret key (required)

Optional Variables:

  • SPACE_REGION - Storage region (default: us-east-1)
  • DB_TRANSACTIONS_ENABLED - Enable transactions (auto-detected if unset)
  • LOG_LEVEL - Stored in global config when present (default: info); does not control the library logger — use XRONOX_CORE_LOGS_LEVEL below
  • LOG_FORMAT - Log format: text, json, yaml (default: text)
  • VERSIONING_ENABLED - Enable versioning (default: true)
  • LOGICAL_DELETE_ENABLED - Enable soft delete (default: true)
  • MONGO_MAPPED_ONLY - Store only mapped properties (default: false)
  • ENABLE_XRONOX_CORE_LOGXER - Master switch for this package’s logxer (default: when unset, treated as false). See Logging below.

Logging (@x12i/logxer)

ENABLE_XRONOX_CORE_LOGXER (optional, default false in .env / resolved config)

  • Set to true (e.g. ENABLE_XRONOX_CORE_LOGXER=true) to enable full logxer behavior for the main library and createSingleXronox: per-prefix levels and defaults below apply.
  • When false or omitted, log level is forced to error only (only error lines are emitted; not off / silent).
  • The same variable name is used for both log surfaces so behavior stays consistent.

Per-package verbosity (when the master switch is on) uses a stable prefix and is implemented by @x12i/logxer.

| Surface | Prefix | Canonical env | Legacy (if canonical unset) | |--------|--------|---------------|-----------------------------| | Main library logger | XRONOX_CORE | XRONOX_CORE_LOGS_LEVEL | XRONOX_CORE_LOG_LEVEL | | createSingleXronox | XRONOX_SINGLE | XRONOX_SINGLE_LOGS_LEVEL | XRONOX_SINGLE_LOG_LEVEL |

  • Default when the master switch is on and both canonical and legacy are unset: warn (warn and error only), not info.
  • Silence this package’s diagnostics: set canonical to off, none, or silent.
  • More detail: e.g. XRONOX_CORE_LOGS_LEVEL=info or debug.

Cross-cutting options (where logs go, format, file, unified sink) stay host-level — this repo wires LOG_FORMAT, LOG_TO_FILE, LOG_FILE, LOG_TO_UNIFIED, DEBUG through @x12i/env into the logger configuration.

ERC 2.0 Compliance

  • ✅ Auto-discovers configuration from environment variables
  • ✅ Type-safe with automatic coercion and validation
  • ✅ Transitive requirements automatically documented
  • ✅ All dependencies are ERC 2.0-compliant
  • ✅ Automatic manifest and .env.example generation

Dependencies:

  • @x12i/xronox-router (ERC 2.0)
  • @x12i/xronox-storage-interface (ERC 2.0)
  • @x12i/xronox-storage-s3 (ERC 2.0)
  • @x12i/logxer (ERC 2.0)
  • @x12i/env (Configuration engine)

Verify ERC Compliance

# Run ERC functionality tests
npm run erc:test

# Verify ERC 2.0 compliance (generates manifest and verifies)
npm run erc:verify

# Generate documentation
npm run erc:docs

Test Coverage:

  • ✅ ERC manifest file exists and has correct structure
  • .env.example file is generated
  • ✅ Configuration initializes in both simple and complex modes
  • ✅ ERC dependencies are correctly listed
  • ✅ ERC validation works correctly

Advanced Mode (Complex Configuration)

For advanced scenarios (multi-tenant, multi-region, routing), create xronox.config.json in your project root. The component will automatically detect and use it (Complex Mode).

Use Complex Mode when:

  • Your data needs routing (multi-tenant, multi-region, sharding)
  • You have multiple MongoDB backends
  • Routing decisions are required based on context (tenantId, region, etc.)
  • You need per-collection feature configuration

Use Simple Mode (Zero-Config) when:

  • Your data doesn't need routing (single backend is sufficient)
  • You have a single MongoDB instance and S3 bucket
  • No multi-tenant or multi-region requirements
  • You want the simplest possible setup

Example xronox.config.json (Complex Mode):

{
  "database": {
    "uri": "ENV.MONGO_URI",
    "dbName": "ENV.MONGO_DB||xronox_demo",
    "transactions": { "enabled": "ENV.DB_TRANSACTIONS_ENABLED:boolean" }
  },
  "storage": {
    "endpoint": "ENV.SPACE_ENDPOINT",
    "region": "ENV.SPACE_REGION||us-east-1",
    "bucket": "ENV.SPACE_BUCKET",
    "accessKey": "ENV.SPACE_ACCESS_KEY",
    "secretKey": "ENV.SPACE_SECRET_KEY"
  },
  "logging": {
    "level": "ENV.LOG_LEVEL||info",
    "format": "ENV.LOG_FORMAT||text",
    "toFile": "ENV.LOG_TO_FILE:boolean||false",
    "filePath": "ENV.LOG_FILE||",
    "toUnified": "ENV.LOG_TO_UNIFIED:boolean||false",
    "debugNamespace": "ENV.DEBUG||"
  },
  "enableXronoxCoreLogxer": "ENV.ENABLE_XRONOX_CORE_LOGXER:boolean||false"
}

Create instances (one per database)

import { createItem, createSingleXronox } from '@x12i/xronox-core';
import type { RouteContext } from '@x12i/xronox-router';

const main = createSingleXronox();
const archive = createSingleXronox({ overrideDbName: 'xronox_demo_archive' });

const ctxUsers: RouteContext = { collection: 'users', dbName: 'xronox_demo', databaseType: 'runtime' };
const ctxOrders: RouteContext = { collection: 'orders', dbName: 'xronox_demo_archive', databaseType: 'runtime' };

await createItem(main, ctxUsers,   { name: 'Alice' },        { jobId: 'job-1' });
await createItem(archive, ctxOrders, { title: 'Order-001' },  { jobId: 'job-2' });

Notes

  • Simple mode is for non-routable data - Single backend, no routing decisions. All operations go to the same MongoDB.
  • ENV is read via @x12i/env; no direct process.env access in application code.
  • Logging uses @x12i/logxer with ENV-configured level/format when ENABLE_XRONOX_CORE_LOGXER=true; otherwise level is error-only.
  • Storage is required by design (JSON is written there).
  • You can create multiple "single" instances safely; each handles exactly one database and one storage bucket.
  • For routable data (multi-tenant, multi-region), use Router Mode with BridgeRouter from @x12i/xronox-router.

Core Features (Implemented & Tested)

CRUD Operations

  • Create - Insert new items with automatic versioning
  • Update - Modify existing items with optimistic locking
  • Delete - Logical delete (soft delete) preserving audit trail
  • Restore - Restore logically deleted items to previous versions
  • Fetch - Retrieve complete records from storage

Storage Externalization

  • Automatic externalization of base64/binary fields to S3-compatible storage
  • Full record assembly on fetch from Mongo head + storage objects
  • Per-key storage mirroring in demos for verification

Configuration-Driven Behavior

  • Transactions - Enable/disable via database.transactions.enabled (auto-detected for replica sets)
  • Mapped-only mode - Toggle via mongoMapping.mappedOnly to store only mapped properties in Mongo
  • DB name separation - Logical database name always from config, never from connection URI
  • Lazy collection creation - Backing collections (versions, counter) created automatically on first write
  • Per-collection features - Configure versioning, storage, shadow collections per collection via collectionMaps

Natural Head Collection UX

  • Works like normal MongoDB - *-head collections behave as primary collections
  • No pre-creation required - Start using collections immediately, backing collections created lazily
  • Graceful degradation - Read operations work even when backing collections don't exist
  • Backwards compatible - Supports both entities and entities_head collection name formats

How It Works:

Lazy collection creation works seamlessly in both Simple Mode (non-routable) and Router Mode (routable):

Simple Mode (createSingleXronox) - Non-Routable Data:

import { createItem, createSingleXronox } from '@x12i/xronox-core';

// Simple mode = single backend, no routing decisions
// Use for data that doesn't need routing (single MongoDB + S3 backend)
const router = createSingleXronox(); // Fixed: one MongoDB URI, one S3 bucket
const ctx: RouteContext = {
  collection: 'users', // or 'users_head' - both work!
  dbName: 'my-db',
  databaseType: 'runtime'
};

// First write - collections created automatically on the single backend
await createItem(router, ctx, { name: 'John' }, { actor: 'system' });
// ✅ Creates: users_head, users_ver, users_counter (if versioning enabled)
// ✅ Always writes to the same MongoDB (no routing logic)
// ✅ Works even if collections didn't exist before

Router Mode (xronox-router) - Routable Data:

import { createItem } from '@x12i/xronox-core';
import { BridgeRouter } from '@x12i/xronox-router';

// Router mode = multiple backends, routing decisions
// Use for data that needs routing (multi-tenant, multi-region, etc.)
const router = new BridgeRouter(/* router config with multiple backends */);
const ctx: RouteContext = {
  collection: 'entities', // or 'entities_head' - both work!
  dbName: 'runtime-db',
  databaseType: 'runtime',
  tenantId: 'tenant-a' // Router uses this to decide which backend
};

// First write - router decides backend, then creates collections there
await createItem(router, ctx, { data: 'value' }, { actor: 'user' });
// ✅ Router selects backend based on tenantId/context
// ✅ Creates collections on the routed backend
// ✅ Respects per-collection feature configuration

Key Distinction:

  • Simple Mode: Non-routable data → single backend, no routing decisions, always same MongoDB
  • Router Mode: Routable data → multiple backends, routing decisions, backend selected by context

Key Points:

  • No setup required - Just start using collections, they're created on first write
  • Configuration-driven - Features (versioning, storage) enabled/disabled per collection
  • Backwards compatible - Existing code with entities_head format continues to work
  • Works everywhere - Simple mode, router mode, multi-tenant, all scenarios

How Lazy Creation Works:

  1. On First Write:

    • createItem(), updateItem(), or deleteItem() is called
    • Code checks if backing collections exist (versions, counter)
    • If missing and enabled in config → creates them automatically
    • Then proceeds with the write operation
  2. On Read:

    • Head collection queries work normally (MongoDB creates collection on first write)
    • Version queries return empty/null if versions collection doesn't exist (graceful)
    • No errors, no collection creation on read (unless createOnRead: true in config)
  3. Collection Naming:

    • Pass 'entities' → creates entities_head, entities_ver, entities_counter
    • Pass 'entities_head' → strips suffix, creates same collections (backwards compatible)
    • No double suffixes, no manual renaming needed

Example: Simple Collection (No Versioning)

// xronox.config.json
{
  "collectionMaps": {
    "simple_data": {
      "features": {
        "versioning": { "enabled": false }
      }
    }
  }
}

// Usage
const ctx: RouteContext = {
  collection: 'simple_data',
  dbName: 'my-db',
  databaseType: 'runtime'
};

await createItem(router, ctx, { name: 'Test' }, { actor: 'user' });
// ✅ Creates: simple_data_head, simple_data_counter
// ❌ Does NOT create: simple_data_ver (versioning disabled)

Example: Advanced Collection (With Versioning)

// xronox.config.json
{
  "collectionMaps": {
    "audited_data": {
      "features": {
        "versioning": { "enabled": true }
      }
    }
  }
}

// Usage
const ctx: RouteContext = {
  collection: 'audited_data',
  dbName: 'my-db',
  databaseType: 'runtime'
};

await createItem(router, ctx, { name: 'Test' }, { actor: 'user' });
// ✅ Creates: audited_data_head, audited_data_ver, audited_data_counter
// ✅ Stores version history automatically

Work Tracking (jobId)

  • Track operations across the call stack with jobId parameter
  • Automatic storage in _system.jobIds array for MongoDB records
  • Enables log correlation, state fetching, and debugging

Quick Start

Basic CRUD Operations

import { createItem, updateItem, deleteItem, getItem } from '@x12i/xronox-core';
import type { BridgeRouter, RouteContext } from '@x12i/xronox-router';

// Setup context
const ctx: RouteContext = {
  collection: 'users',
  dbName: 'my-app-db',
  databaseType: 'runtime',
  tenantId: 'tenant-a'  // Optional: for multi-tenant scenarios
};

// Create a new item
const jobId = `api-request-${Date.now()}`;
const result = await createItem(router, ctx, {
  name: 'John Doe',
  email: '[email protected]',
  profileImage: '<base64-data>'  // Auto-externalized to storage
}, {
  actor: '[email protected]',
  reason: 'New user registration',
  jobId  // Track this work
});

console.log(`Created: ${result.id}, version ${result.ov}`);
// Mongo head points to storage; profileImage externalized with _key and _url

// Fetch complete record (assembled from Mongo + Storage)
const user = await getItem(router, ctx, result.id);
// user includes all fields, with storage data fetched automatically

// Update the item
await updateItem(router, ctx, result.id, {
  name: 'John Updated'
}, {
  expectedOv: result.ov,  // Optimistic locking
  actor: 'system',
  reason: 'User profile update',
  jobId
});

// Logical delete (soft delete)
await deleteItem(router, ctx, result.id, {
  actor: '[email protected]',
  reason: 'User requested deletion',
  jobId
});

Pagination (Cursor-Based)

For efficient pagination over large collections, use the cursor-based pagination API:

import { Repos } from '@x12i/xronox-core';

// Get repository instance
// Note: Collection name can be with or without _head suffix (backwards compatible)
const routeInfo = router.route(ctx);
const mongoClient = await router.getMongoClient(routeInfo.mongoUri);
const mongo = mongoClient.db(ctx.dbName || 'default');
const repos = new Repos(mongo, ctx.collection || 'default'); // Works with 'entities' or 'entities_head'

// First page (newest items first)
const page1 = await repos.listHeadsPaged({}, 20);
console.log(`Items: ${page1.items.length}`);
console.log(`Has next: ${page1.pageInfo.hasNextPage}`);

// Next page (use endCursor from previous page)
if (page1.pageInfo.hasNextPage) {
  const page2 = await repos.listHeadsPaged({}, 20, page1.pageInfo.endCursor);
  // Continue pagination...
}

// With filter (e.g., active users only)
const activePage = await repos.listHeadsPaged(
  { 'metaIndexed.status': 'active' },
  20
);

// Paginate version history for an item
const versionPage = await repos.listVersionsPaged(itemId, 10);
console.log(`Versions: ${versionPage.items.length}`);

Why cursor-based?

  • Scales to millions of documents (no skip/offset overhead)
  • Stable results even when data changes between requests
  • Works efficiently with MongoDB's indexed _id field
  • Industry best practice for large datasets

Configuration

Create a config file (e.g., xronox.config.json):

{
  "database": {
    "uri": "ENV.MONGO_URI",
    "dbName": "ENV.MONGO_TESTING_DB||xronox_demo",
    "transactions": {
      "enabled": "ENV.DB_TRANSACTIONS_ENABLED:boolean"
    }
  },
  "mongoMapping": {
    "mappedOnly": "ENV.MONGO_MAPPED_ONLY:boolean||false"
  },
  "storage": {
    "endpoint": "ENV.SPACE_ENDPOINT",
    "bucket": "ENV.SPACE_BUCKET",
    "region": "ENV.SPACE_REGION",
    "accessKey": "ENV.SPACE_ACCESS_KEY",
    "secretKey": "ENV.SPACE_SECRET_KEY"
  },
  "collectionMaps": {
    "entities": {
      "indexedProps": ["name", "status"],
      "features": {
        "versioning": { "enabled": true },
        "storage": { "enabled": true, "threshold": 1024 },
        "lazyCreation": { "enabled": true, "createOnRead": false }
      }
    },
    "simple_collection": {
      "indexedProps": ["name"],
      "features": {
        "versioning": { "enabled": false }
      }
    }
  }
}

Per-Collection Feature Configuration:

  • versioning.enabled - Enable/disable versioning for this collection (default: true)
  • storage.enabled - Enable/disable storage externalization (default: true)
  • storage.threshold - Size threshold for externalization in bytes (default: 1024)
  • lazyCreation.enabled - Enable lazy collection creation (default: true)
  • lazyCreation.createOnRead - Create collections on read operations (default: false)

Environment variables:

# MongoDB (connection URI and logical DB name are SEPARATE)
MONGO_URI=mongodb://localhost:27017
MONGO_TESTING_DB=my-test-db

# Transactions (optional; auto-detected for replica sets if unset)
DB_TRANSACTIONS_ENABLED=false

# Mapped-only mode (optional; default false)
MONGO_MAPPED_ONLY=false

# Storage
SPACE_ENDPOINT=https://s3.amazonaws.com
SPACE_BUCKET=my-bucket
SPACE_REGION=us-east-1
SPACE_ACCESS_KEY=your-key
SPACE_SECRET_KEY=your-secret

Testing & Demos

The real demos have moved to a peer package (outside this repository). This library focuses on core expertise.

  • Demos enforce Rules 25/26/27 in the demos package (real execution, evidence, timeouts).
  • This package enforces infrastructure and boundaries (Rule 28, @x12i/env, @x12i/logxer, Poiesis).

See the demos package README for how to run demos and inspect evidence.

Architecture

This package follows the Poiesis methodology with clear component boundaries:

Primary Component: DataComponent

Expertise: Data persistence and retrieval with storage externalization

Sub-Components:

  • CrudOperations (src/crud.ts) - Create, update, delete, restore operations
  • RepositoryManagement (src/repos.ts) - MongoDB collection management
  • TransactionLocking (src/lock-manager.ts) - Concurrency control
  • StorageExternalization (inline in crud.ts) - Base64 field externalization

Helper Components:

  • ConfigurationHelper (src/configuration.helper.ts) - Config management via @x12i/env
  • ValidationHelper (src/validation.helper.ts) - Data validation
  • TransactionHelper (src/transaction.helper.ts) - Transaction management
  • SystemHeaderHelper (src/system-header.helper.ts) - System metadata (_system field)

Planned Features

See PLANNED_FEATURES.md for features under consideration or development:

  • Versioning & history browsing (external package)
  • Collection restore to CV/timestamp (external package)
  • Search & pagination (external package)
  • Analytics/counters (external package)
  • Multitenancy formalization (router addon/doc pattern)
  • Concurrency demo expansion

Documentation

Support

License

MIT


Built with Poiesis methodology - Clear component boundaries, single expertise per component, and composable architecture for maintainable, testable, and scalable database operations.