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

@yadah/data-manager

v0.2.0

Published

Yadah data manager to co-ordinate backend subsystems and domains

Readme

yadah/data-manager

Provides logic for configuring an services's data layer, and creating "domain classes" to provide a standard way for front-ends to interact with subsystems.

Usage

Create domain classes

// my-package/domains.js
import { Domain } from "@yadah/data-manager";

export class DomainA extends Domain {
  doATask() {
    this.logger.info("in doATask");
  }
}

export class DomainB extends Domain {
  async doBTask() {
    await this.knex("tableB").insert({ text: "in doBTask" });
  }
}

Create a data manager

// my-package/index.js
import DataManager from "@yadah/data-manager";
import createLogger from "@yadah/subsystem-logger";
import createKnex from "@yadah/subsystem-knex";
import * as modules from "./domains.js";

// setup subsystems
export const logger = createLogger(); // example
export const knex = createKnex(); // example
const subsystems = { logger, knex };

// initialise and boot the data manager
const dataManager = new DataManager(subsystems);
export const domains = dataManager.boot(modules);

// life-cycle functions to start and stop subsystems and domains
export async function startup() {
  await dataManager.startup();
}

export async function shutdown() {
  await dataManager.shutdown();
  await knex.destroy();
}

Access data package exports

// other-package/example.js
import { domains, startup, shutdown } from "my-package";

await startup();
domains.DomainA.doATask();
await domains.DomainB.doBTask();
await shutdown();

Mixins

Mixins are used to create common logic for domains.

Example: the ListenerMixin will call registerListeners() during the boot lifecycle, and will automatically remove listeners during shutdown.

// my-package/SomeDomain.js
import { Domain } from "@yadah/data-manager";
import ListenerMixin from "@yadah/domain-listener";
import { pipe } from "@yadah/mixin";

const mixins = pipe(Domain, ListenerMixin);
export class SomeDomain extends mixins {
  registerListeners() {
    this.on("someEvent", () => this.handleSomeEvent());
  }
  handleSomeEvent() {
    // code to handle 'someEvent' events
  }
}

Creating a mixin

A mixin is a function that returns a class that extends a supplied class.

The dedupe() function is a wrapper for mixin functions that ensures they will wrap a class only once. This allows mixin depdendencies to be well defined.

// my-package/SomeMixin.js
import { dedupe } from "@yadah/mixin";

function SomeMixin(superclass) {
  return class Some extends superclass {
    someMixinFn() {
      // mixin logic
    }
  };
}
export default dedupe(SomeMixin);

A mixin can depend on another mixin by extending the superclass:

// my-package/SomeMixin.js
import { dedupe, pipe } from "@yadah/mixin";
import OtherMixin from "other-package";

function SomeMixin(superclass) {
  const mixins = pipe(superclass, OtherMixin);
  return class Some extends mixins {
    someMixinFn() {
      const result = this.otherMixinFn();
      //
    }
  };
}

export default dedupe(SomeMixin);

Domain class life-cycle functions

The Domain class provides three life-cycle functions:

  1. boot()
  2. startup()
  3. shutdown()

The boot() function is executed synchronously. All subsystems and other domain classes are visible via this. This function is typically used to allow registering behaviours defined by mixins. boot() is called when the DataManager.boot() function is called - typically during the services's data-layer setup. boot() should be passed an object containing "domain classes" which will be created as singletons and stored on the this.domains object. boot() returns an object containing the domain class singletons.

The startup() function may be asynchronous. The boot() function should be called prior to startup(). This function is called on each domain class singleton when the DataManager.startup() function is called.

The shutdown() function may be asynchronous. This function is called on each domain class singleton when the DataManager.shutdown() function is called.