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 🙏

© 2025 – Pkg Stats / Ryan Hefner

nx-remote-json

v1.0.2

Published

A unified API to read, write, and mirror JSON objects across disk, S3-compatible storage, and MongoDB

Readme

remote-json

A unified TypeScript SDK for reading, writing, and mirroring JSON objects across multiple backends: local filesystem (disk), S3-compatible object storage, and MongoDB.

Package Information

  • Package: nx-remote-json
  • Version: 1.0.1
  • Runtime: Node.js 18+
  • Language: TypeScript 5+

Features

  • Unified API: Single interface for three different storage backends
  • Type-safe: Full TypeScript support with comprehensive type definitions
  • Flexible routing: Map logical routers to backend-specific locations
  • Mirroring: Sync JSON objects between backends
  • Atomic operations: Safe file writes and upsert operations

Installation

npm install nx-remote-json

Requirements

  • Node.js 18+
  • TypeScript 5+

Quick Start

import { 
  createRemoteJsonClient,
  type RemoteJsonConfig 
} from "nx-remote-json";

const config = {
  disk: {
    rootLocation: "/data/remote-json",
    defaultExtension: ".json",
    mapping: [
      { jsonRouter: "settings", folder: "settings" },
      { jsonRouter: "dashboards", folder: "dashboards" }
    ]
  }
};

const client = createRemoteJsonClient(config);

// Read
const settings = await client.read({
  mode: "disk",
  jsonRouter: "settings",
  jsonKey: "user-123"
});

// Write
await client.write({
  mode: "disk",
  jsonRouter: "settings",
  jsonKey: "user-123",
  payload: { theme: "dark", language: "en" }
});

Configuration

Disk Backend

{
  disk: {
    rootLocation: "/data/remote-json",  // Base directory
    defaultExtension: ".json",          // Optional, defaults to ".json"
    mapping: [
      { jsonRouter: "settings", folder: "settings" },
      { jsonRouter: "dashboards", folder: "dashboards" }
    ]
  }
}

Path resolution: rootLocation/folder/jsonKey.json

Storage Backend (S3-compatible)

{
  storage: {
    region: "eu-central-1",
    endpoint: "https://s3.example.com",
    forcePathStyle: true,
    accessKey: "ACCESS_KEY",
    secretKey: "SECRET_KEY",
    bucket: "my-remote-json",
    defaultExtension: ".json",
    mapping: [
      { jsonRouter: "settings", folder: "settings" },
      { jsonRouter: "dashboards", folder: "dashboards" }
    ]
  }
}

Object key resolution: folder/jsonKey.json

Database Backend (MongoDB)

{
  database: {
    mongoUri: "mongodb://user:pass@localhost:27017",
    mongoDb: "remote_json",
    mapping: [
      { jsonRouter: "settings", collectionName: "settings" },
      { jsonRouter: "dashboards", collectionName: "dashboards" }
    ],
    queryFilters: [
      {
        field: "router",
        operator: "eq",
        valueSource: "literal",
        literalValue: "settings"
      },
      {
        field: "key",
        operator: "eq",
        valueSource: "jsonKey",
        transform: "none"
      }
    ]
  }
}

Filter construction: Filters are built from queryFilters templates and combined with $and. At least one filter must use valueSource: "jsonKey".

Write behavior: Filter fields are automatically injected into documents during writes, ensuring the same jsonKey can always re-find the document.

Type Exports

The package exports the following TypeScript types:

import type {
  RemoteJsonConfig,        // Main configuration type
  RemoteJsonMode,          // "disk" | "storage" | "database"
  RemoteJsonClient,        // Client interface
  ReadRequest,             // Read operation request
  WriteRequest,            // Write operation request
  MirrorRequest,           // Mirror operation request
  MirrorResult,            // Mirror operation result
  DiskBackendConfig,       // Disk backend configuration
  StorageBackendConfig,    // Storage backend configuration
  DatabaseBackendConfig,   // Database backend configuration
  RemoteJsonError,         // Error class
  RemoteJsonErrorCode,     // Error code type
} from "nx-remote-json";

Important: The main configuration type is RemoteJsonConfig, not RemoteJsonClientConfig.

API Reference

read<T>(req: ReadRequest): Promise<T | null>

Reads a JSON object from the specified backend.

const data = await client.read<MyType>({
  mode: "disk",
  jsonRouter: "settings",
  jsonKey: "user-123"
});

if (data === null) {
  console.log("Not found");
}

write<T>(req: WriteRequest<T>): Promise<void>

Writes a JSON object to the specified backend.

await client.write({
  mode: "storage",
  jsonRouter: "dashboards",
  jsonKey: "team-A",
  payload: {
    title: "Team A Dashboard",
    widgets: []
  }
});

mirror(req: MirrorRequest): Promise<MirrorResult>

Mirrors JSON objects from a master backend to target backends.

// Mirror one object
const result = await client.mirror({
  masterMode: "disk",
  jsonRouter: "settings",
  jsonKey: "user-123",
  targetModes: ["storage", "database"],
  overwriteExisting: true
});

// Mirror all objects in a router
const result = await client.mirror({
  masterMode: "disk",
  jsonRouter: "settings",
  targetModes: ["storage"]
});

// Mirror all routers
const result = await client.mirror({
  masterMode: "disk",
  targetModes: ["storage", "database"]
});

Mirror options:

  • masterMode: Source backend (required)
  • jsonRouter: Optional, limits to specific router
  • jsonKey: Optional, limits to specific key
  • targetModes: Optional, defaults to all configured modes except master
  • overwriteExisting: Optional, defaults to true

Result structure:

{
  items: [
    {
      jsonRouter: "settings",
      jsonKey: "user-123",
      sourceMode: "disk",
      targetMode: "storage",
      status: "created" | "updated" | "skipped" | "failed",
      error?: string
    }
  ]
}

Error Handling

All methods throw RemoteJsonError with the following error codes:

  • CONFIG_ERROR: Configuration is invalid
  • MAPPING_NOT_FOUND: No mapping found for the specified jsonRouter
  • BACKEND_NOT_CONFIGURED: Requested backend is not configured
  • SERIALIZATION_ERROR: Failed to serialize JSON payload
  • DESERIALIZATION_ERROR: Failed to parse JSON response
  • BACKEND_IO_ERROR: Backend I/O operation failed
import { RemoteJsonError } from "nx-remote-json";

try {
  await client.write({ ... });
} catch (err) {
  if (err instanceof RemoteJsonError) {
    console.error(`Error code: ${err.code}`);
    console.error(`Message: ${err.message}`);
    if (err.cause) {
      console.error(`Cause:`, err.cause);
    }
  }
}

Examples

Multi-backend Configuration

const config = {
  disk: {
    rootLocation: "./data",
    mapping: [
      { jsonRouter: "settings", folder: "settings" }
    ]
  },
  storage: {
    region: "us-east-1",
    endpoint: "https://s3.amazonaws.com",
    forcePathStyle: false,
    accessKey: process.env.AWS_ACCESS_KEY_ID!,
    secretKey: process.env.AWS_SECRET_ACCESS_KEY!,
    bucket: "my-bucket",
    mapping: [
      { jsonRouter: "settings", folder: "settings" }
    ]
  },
  database: {
    mongoUri: process.env.MONGODB_URI!,
    mongoDb: "app_db",
    mapping: [
      { jsonRouter: "settings", collectionName: "settings" }
    ],
    queryFilters: [
      {
        field: "key",
        operator: "eq",
        valueSource: "jsonKey"
      }
    ]
  }
};

const client = createRemoteJsonClient(config);

MongoDB with ObjectId

{
  database: {
    // ... other config
    queryFilters: [
      {
        field: "_id",
        operator: "eq",
        valueSource: "jsonKey",
        transform: "objectId"  // Converts jsonKey to ObjectId
      }
    ]
  }
}

Mirroring with Skip Existing

// Only create new objects, skip existing ones
const result = await client.mirror({
  masterMode: "disk",
  jsonRouter: "settings",
  overwriteExisting: false  // Skip if already exists
});

const created = result.items.filter(i => i.status === "created");
const skipped = result.items.filter(i => i.status === "skipped");

License

MIT