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

@decaf-ts/for-nano

v0.5.14

Published

decaf-ts persistence adapter for CouchDB via nano

Readme

Banner

Decaf's Nano (CouchDB) Module

A lightweight adapter layer and utilities to use CouchDB via the Nano client within the decaf-ts ecosystem. It provides a NanoAdapter with repository-friendly CRUD, bulk operations, indexing, user/database management helpers, and a change feed dispatcher, plus typed flags and configuration for ergonomic, testable data access.

Release docs refreshed on 2025-11-26. See workdocs/reports/RELEASE_NOTES.md for ticket summaries.

Licence GitHub language count GitHub top language

Build & Test CodeQLSnyk Analysis Pages builder .github/workflows/release-on-tag.yaml

Open Issues Closed Issues Pull Requests Maintained

Forks Stars Watchers

Node Version NPM Version

Documentation available here

Description

This package integrates CouchDB via the Nano client into the decaf-ts data stack. It exposes a focused set of primitives that make CouchDB usage consistent with other decaf-ts backends (TypeORM, HTTP, Pouch, etc.), while retaining Nano’s flexibility.

Core elements and their intents:

  • NanoAdapter

    • Bridges decaf-ts Repository operations with Nano’s DocumentScope API.
    • Implements repository-friendly CRUD: create, read, update, delete, plus bulk variants (createAll, readAll, updateAll, deleteAll).
    • Preserves and manages CouchDB revision metadata transparently via PersistenceKeys.METADATA and CouchDBKeys.REV.
    • Provides raw Mango query capability (raw) and index management (index).
    • Offers connection and administration helpers: connect, createDatabase, deleteDatabase, createUser, deleteUser.
    • Exposes Dispatch() to construct a NanoDispatch for change feed observation.
    • Normalizes operation flags via flags(), ensuring user context is propagated from NanoFlags to the underlying operations.
  • NanoDispatch

    • A Dispatch implementation that subscribes to CouchDB’s continuous changes feed through Nano.
    • Parses change feed frames, groups them by table and operation (CREATE/UPDATE/DELETE), and notifies observers through updateObservers.
    • Handles reconnection attempts and keeps track of the last processed update step (observerLastUpdate) for resilience.
  • NanoRepository

    • A typed alias that binds Repository to the Nano-specific types: MangoQuery, NanoAdapter, NanoFlags, and Context.
    • Enables consumers to use a familiar Repository API with CouchDB when paired with NanoAdapter.
  • Types and constants

    • NanoFlags extends RepositoryFlags with a required user object (name, roles?) for consistent auth context propagation.
    • NanoConfig captures the minimal connection shape (user, password, host, dbName) for setting up adapters.
    • NanoFlavour identifies this backend for selection in multi-backend setups.
    • VERSION exposes the package version string.

Design considerations:

  • Predictable metadata management: CouchDB’s _rev is captured in internal metadata, avoiding accidental leakage into domain models.
  • Bulk operations are error-aware: mixed success/failure responses are aggregated and surfaced as InternalError, preserving the failing reasons from Nano.
  • Testability: All core behaviors (CRUD, bulk, raw, admin helpers, dispatch) are covered by unit tests and written to be easily mocked.
  • Interop-first: Reuses shared types from @decaf-ts/for-couchdb (e.g., MangoQuery, CouchDBKeys) so that query building and index generation are consistent across CouchDB-based adapters.

How to Use

This guide shows practical, non-duplicated examples for all public APIs in @decaf-ts/for-nano using the repository pattern. The adapter class is not meant to be accessed directly; instead, always obtain a repository with Repository.forModel(Model).

Prerequisites:

  • CouchDB server reachable from your app.
  • Install the package: npm i @decaf-ts/for-nano @decaf-ts/for-couchdb @decaf-ts/core @decaf-ts/db-decorators @decaf-ts/decorator-validation nano
  • Importing from @decaf-ts/for-nano registers the Nano backend with the core Repository system.

  1. Define a model and get a repository

Description: Declare a model with table/primary-key decorators and get a Nano-powered repository for it. The flavour is auto-wired by importing @decaf-ts/for-nano.

import {
  BaseModel,
  Repository,
  pk,
  uses,
} from "@decaf-ts/core";
import { model, Model, ModelArg, required } from "@decaf-ts/decorator-validation";
import type { NanoRepository } from "@decaf-ts/for-nano";

@uses("nano")
@model()
class UserModel extends BaseModel implements Model {
  @pk({ type: "String" })
  id!: string; // primary key

  @required()
  name!: string;

  constructor(arg?: ModelArg<UserModel>) {
    super(arg);
  }
}

const repo: NanoRepository<UserModel> = Repository.forModel<UserModel, NanoRepository<UserModel>>(UserModel);
  1. Flags with user context

Description: Pass NanoFlags in repository calls; the user info is propagated to operations by the adapter under the hood.

import type { NanoFlags } from "@decaf-ts/for-nano";

const flags: NanoFlags = {
  user: { name: "tester", roles: ["writer"] },
};
  1. CRUD: create and read a single document

Description: Insert a document and read it back. CouchDB revisions are stored in PersistenceKeys.METADATA transparently.

import { PersistenceKeys } from "@decaf-ts/core";

const created = await repo.create(new UserModel({ id: "user:1", name: "Ada" }));
// created[PersistenceKeys.METADATA] contains the new revision string, e.g., "1-a"

const loaded = await repo.read("user:1");
console.log(loaded.name);
  1. Bulk create and bulk read

Description: Insert multiple documents and then fetch them by IDs. Bulk operations aggregate errors.

const users = [
  new UserModel({ id: "user:2", name: "Lin" }),
  new UserModel({ id: "user:3", name: "Grace" }),
];
const createdMany = await repo.createAll(users);

const fetchedMany = await repo.readAll(["user:2", "user:3"]);
  1. Update and updateAll

Description: Update requires the previous revision in metadata. The new revision is written back into metadata.

let u = await repo.read("user:1");
// ... mutate
u.name = "Ada Lovelace";
// u already has PersistenceKeys.METADATA from read()
u = await repo.update(u);

// Bulk update requires each model to carry its matching metadata
const u2 = await repo.read("user:2");
const u3 = await repo.read("user:3");
const updatedMany = await repo.updateAll([u2, u3]);
  1. Delete and deleteAll

Description: Delete a single document, or delete in bulk by IDs.

const deleted = await repo.delete("user:3");

const deletedMany = await repo.deleteAll(["user:1", "user:2"]);
  1. Query with selectors (instead of raw Mango)

Description: Use the Repository query API to filter and project results.

import { Condition, OrderDirection } from "@decaf-ts/core";

// Select all as full UserModel objects
const all = await repo.select().execute();

// Select only specific attributes
const projected = await repo.select(["name"]).execute();

// Conditional queries
const nameEq = Condition.attribute<UserModel>("name").eq("Ada Lovelace");
const named = await repo.select().where(nameEq).execute();

// Ordering (requires proper indexes configured for CouchDB)
const ordered = await repo.select().orderBy(["name", OrderDirection.ASC]).execute();
  1. Observe changes via repository

Description: Subscribe to CREATE/UPDATE/DELETE events using the Observer interface. The repository wires Nano’s change feed internally.

import type { Observer } from "@decaf-ts/core";
import { OperationKeys } from "@decaf-ts/db-decorators";

const observer: Observer = {
  async refresh(table: string, operation: OperationKeys | string, ids: string[]) {
    if (operation.toString() === OperationKeys.DELETE.toString()) {
      console.log(`Deleted from ${table}:`, ids);
    }
  },
};

await repo.observe(observer);
// ... later
await repo.unObserve(observer);
  1. Choose the backend via NanoFlavour

Description: Use NanoFlavour as an identifier in multi-backend setups.

import { NanoFlavour } from "@decaf-ts/for-nano";
console.log(NanoFlavour); // "nano"
  1. Use NanoRepository typing

Description: Bind your model type to a repository powered by the Nano backend.

import type { NanoRepository } from "@decaf-ts/for-nano";
import type { Model } from "@decaf-ts/decorator-validation";

class MyModel implements Model {
  _id!: string;
}

let myRepo!: NanoRepository<MyModel>;
  1. Access package VERSION

Description: Read the module’s version string if you need it for diagnostics.

import { VERSION } from "@decaf-ts/for-nano";
console.log("for-nano version:", VERSION);

Advanced (optional): Administration helpers

Description: If you must manage CouchDB resources, @decaf-ts/for-nano exports static helpers on NanoAdapter (no direct instantiation required). These are not part of the Repository API.

import { NanoAdapter } from "@decaf-ts/for-nano";

// Build a Nano (CouchDB) connection
const url = NanoAdapter.connect("admin", "secret", "localhost:5984", "http");

// Ensure a database exists / manage users
await NanoAdapter.createDatabase(url, "mydb");
// ... createUser/deleteUser, deleteDatabase, etc.

Coding Principles

  • group similar functionality in folders (analog to namespaces but without any namespace declaration)
  • one class per file;
  • one interface per file (unless interface is just used as a type);
  • group types as other interfaces in a types.ts file per folder;
  • group constants or enums in a constants.ts file per folder;
  • group decorators in a decorators.ts file per folder;
  • always import from the specific file, never from a folder or index file (exceptions for dependencies on other packages);
  • prefer the usage of established design patters where applicable:
    • Singleton (can be an anti-pattern. use with care);
    • factory;
    • observer;
    • strategy;
    • builder;
    • etc;

Release Documentation Hooks

Stay aligned with the automated release pipeline by reviewing Release Notes and Dependencies after trying these recipes (updated on 2025-11-26).

Related

decaf-ts for pouch core decorator-validation db-decorators

Social

LinkedIn

Languages

TypeScript JavaScript NodeJS ShellScript

Getting help

If you have bug reports, questions or suggestions please create a new issue.

Contributing

I am grateful for any contributions made to this project. Please read this to get started.

Supporting

The first and easiest way you can support it is by Contributing. Even just finding a typo in the documentation is important.

Financial support is always welcome and helps keep both me and the project alive and healthy.

So if you can, if this project in any way. either by learning something or simply by helping you save precious time, please consider donating.

License

This project is released under the Mozilla Public License 2.0.

By developers, for developers...