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 🙏

© 2024 – Pkg Stats / Ryan Hefner

dyal

v1.0.11

Published

DYAL for Decouple Your Application Layer. It's a ligth & simple application layer framework with CQRS utilities

Downloads

14

Readme

DYAL

test

Simple application layer framework with CQRS tooling

This framework helps you Decouple Your Application Layer (DYAL) from your presentation layer.

It is inspired from Koa for the middlewares implementation except that it does not couple your application to HTTP presentation layer. It let you free to choose any way to expose your app commands with HTTP, CLI, gRPC, etc...

https://nodei.co/npm/dyal.png?downloads=true&downloadRank=true&stars=true

npm install dyal

Documentation:

Basic Example:

You can find this example and more advanced here

// Declare the dependencies you will inject into your app.
type AppDependencies = {
  database: DBConnection;
  logger: Logger;
};

// Build the app and inject dependencies.
const app = createApp({
  database,
  logger,
});

// Mount handlers and middelwares to handle you app's use cases.
app.use(async (ctx: any) => {
  const results = await ctx.dependencies.database.query('SELECT * FROM ...');
  ctx.result = results;
});

Typed Context Middlware Example:

You can type your middleware's context to know which UseCase it will handle, what result it must return and which are the dependencies that are available on the context.

You can find this example and more advanced here

import { Command, Context, Next } from 'dyal';
import { AppDependencies, GameObject } from '..';

type AddItemContext = Context<AppDependencies, AddItemCommand, AddItemResult>;

export interface AddItemCommand extends Command {
  name: 'AddItem';
  payload: {
    item: GameObject;
  };
}

export type AddItemResult = 'Inventory is full' | 'Item added';

export async function addItemMiddleware(
  context: AddItemContext,
  next: Next,
): Promise<void> {
  const { inventory } = context.dependencies;
  const { useCase } = context;

  if (useCase.type === 'command' && useCase.name !== 'AddItem') {
    await next();
    return;
  }

  const { item } = useCase.payload;

  if (inventory.items.length >= 3) {
    context.result = 'Inventory is full'; // Write the result in context.result
    return;
  }

  inventory.items.push(item);

  context.result = 'Item added'; // Write the result in context.result
  return;
}

As it is not very practical to always filter use cases in each middlewares. DYAL provides CommandBus and QueryBus. These objects allows you to have two distinct middleware stacks for commands an queries and will handle the routing for you so you won't need to do that anymore:

if (useCase.type === 'command' && useCase.name !== 'AddItem') {
  await next();
  return;
}

Notice that you are not forced to use them and you can write your own middlewares to handle use cases on your app.

Command & Query Bus Example:

You can find this example and more advanced here

  const dependencies: AppDependencies = { logger: console.log };

  const app = createApp(dependencies);

  const commandBus: CommandBus = createCommandBus();
  commandBus.register('CountCommand', countCommandHandler);

  const queryBus: QueryBus = createQueryBus();
  queryBus.register('GetCountQuery', getCountQueryHandler);

  app.use(loggerMiddleware);
  app.on('command').use(commandBus.middleware);
  app.on('query').use(queryBus.middleware);

  const countCommand: CountCommand = {
    actionType: 'command',
    name: 'CountCommand',
    payload: {
      count: 5,
    },
  };

  const resultCount = await app.execute<CountCommandResult>(countCommand);
  console.log('resultCount:', resultCount.total);

  const resultGetCount: GetCountQueryResult = await app.execute(getCountQuery);
  console.log('resultGetCount:', resultGetCount.count);
}

Command & Query handlers examples:

Notice that by using CommandBus and QueryBus. You are not writting middlewares but command and query handlers. Their function signature is a bit different as they are not returning a Promise<void> and writing to the context.result. Instead they just return directly their expected return type: Promise<AddItemResult>. It's the command or query bus that will write the context.result for you.

Here is the same example as above, with command handler implementation:

import { Command, Context, Next } from 'dyal';

import { AppDependencies, GameObject } from '..';

type AddItemContext = Context<AppDependencies, AddItemCommand, AddItemResult>;

export interface AddItemCommand extends Command {
  name: 'AddItem';
  payload: {
    item: GameObject;
  };
}

export type AddItemResult = 'Inventory is full' | 'Item added';

export async function addItemHandler(
  context: AddItemContext,
): Promise<AddItemResult> {
  const { inventory } = context.dependencies;
  const { useCase } = context;

  const { item } = useCase.payload;

  if (inventory.items.length >= 3) {
    return 'Inventory is full'; // Return directly the expected return type
  }

  inventory.items.push(item);

  return 'Item added'; // Return directly the expected return type
}

Middlewares:

You can create your own middleware like this:

const dependencies: AppDependencies = { logger: console.log };

async function myLoggerMiddleware(
  ctx: Context<any, AppDependencies, any>,
  next: Next,
): Promise<void> {
  const { logger } = ctx.dependencies;
  logger(`Executing use case: ${ctx.useCase.type} ${ctx.useCase.name}`);
  await next();
}

const app = createApp(dependencies);

app.use(myLoggerMiddleware);

Publish a new version:

  • Bump package.json version
  • npm run build
  • Commit
  • Release on github