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

@s-ui/domain

v2.19.0

Published

SDK for creating domains

Downloads

9,764

Readme

sui-domain

Backbone for creating a domain that complains with the guidelines of Schibsted Spain

Motivation

sui-domain provides:

  • Avoid repeating boilerplate code by extracting some on this library.
  • Enforce all to follow same rules while creating a new domain.
  • A HttpFetcher to make http requests
  • Set of domain objects to extend
  • A utility to create an entry point

Installation

$ npm install @s-ui/domain --save

Using EntryPoint

import {EntryPointFactory} from '@s-ui/domain'

// useCases is an object with a key with the name of the use case
// and an array with a function to import the factory and the
// useCase name as string
const useCases = {
  current_user: [() => import('./user/UseCases/factory'), 'currentUserUseCase'],
  products_search: [
    () => import('./search/UseCases/factory'),
    'productsSearchUseCase'
  ],
  real_estate_detail: [
    () => import('./detail/UseCases/factory'),
    'realEstateDetailUseCase'
  ]
}

// config could be a simple object or a more complicated
// creation like a class Config with methods to get and set
const config = {
  DETAIL_ENDPOINT: 'http://api.url.com/detail'
}

// that returns you an instantiable EntryPoint class
const EntryPoint = EntryPointFactory({config, useCases})
const domain = new EntryPoint()

// if you don't want to share the config between instances
// you could pass the config directly to the constructor
// useful if you're mutating the config for storing values
const EntryPoint = EntryPointFactory({useCases})
const domain = new EntryPoint({config})

Injecting a logger to our domain

In order to increase the observability of your domain, you can pass a custom logger to your domain instance and it will be injected on each UseCase factory. Following the example of previous section:

How to inject the logger to your domain?

// Logger mock example
const logger = {
  log: () => console.log('⚠️')
}

const EntryPoint = EntryPointFactory({config, useCases, logger})
const domain = new EntryPoint()

How use it on your domain?

// Your factory file
import EmptyUseCase from './EmptyUseCase.js'

export default ({config, logger}) => new EmptyUseCase({config, logger})

// Your UseCase implementation
export default class UseCase {
  constructor({config, logger}) {
    this._config = config
    this._logger = logger
  }

  execute() {
    this._logger.log() // Logger ready to rock! 🎸
    return Promise.resolve(true)
  }
}

Injecting a pde to our domain

In order to allow your domain to work with experiments and feature flags, you can pass a custom pde to your domain instance and it will be injected on each UseCase factory.

How to inject the pde to your domain?

// PDE mock example
const pde = {
  isFeatureEnabled: ({featureKey}) => true,
  getVariation: ({name}) => 'experimentVariation'
}

const EntryPoint = EntryPointFactory({config, useCases, pde})
const domain = new EntryPoint()

How to use it on your domain?

// Your factory file
import EmptyUseCase from './EmptyUseCase.js'

export default ({config, pde}) => new EmptyUseCase({config, pde})

// Your UseCase implementation
export default class UseCase {
  constructor({config, pde}) {
    this._config = config
    this._pde = pde
  }

  execute() {
    const {isActive} = this._pde.isFeatureEnabled({featureKey: 'FeatureFlagKey'})
    return isActive ? true : false
  }
}

Using Fetcher

import {FetcherFactory} from '@s-ui/domain'
import UserEntitiesFactory from '../../user/Entities/factory'
import UserValueObjectsFactory from '../../user/ValueObjects/factory'

import HTTPUserRepository from './HTTPUserRepository'

export default class UserRepositoriesFactory {
  static hTTPUserRepository = ({config}) =>
    new HTTPUserRepository({
      config,
      fetcher: FetcherFactory.httpFetcher(),
      userEntityFactory: UserEntitiesFactory.userEntity,
      emptyUserValueObjectFactory: UserValueObjectsFactory.emptyUserValueObject
    })
}

Fetcher exceptions interception

Aditionally, it's possible to require a special version of the http fetcher with which is possible to intercept all errors in one single point of the application.

This feature allows to handle generic http errors in a central and unique function of the web application.

For example, this could be useful if it's needed to perform a specific action every time a 401 status code is retrieved as a result of an http request. (i.e. to redirect the user back to the login page)

How to require the interceptable fetcher

To be able to use this feature, instead of initializing the fetcher normally, it is needed to invoke the following method of the FetcherFactory class:

const fetcher = FetcherFactory.interceptableHttpFetcher()

The interceptableHttpFetcher is fully retrocompatible with the standard httpFetcher class, so there is no need to adapt any code before doing this change.

Setting a function to intercept errors

Once the interceptableHttpFetcher has been required and is being used to perform http requests, it's possible to set a function that will be invoked every time an error occurs when performing an http request.

This is the way the callback function can be defined:

fetcher.setErrorInterceptor({
  callback: error => {
    if (result.isAxiosError === true) {
      const statusCode = result.response.status
      // Do something...
    }
  }
})

Using a domain object

import {UseCase} from '@s-ui/domain'

export default class CurrentUserUseCase extends UseCase {
  constructor({service} = {}) {
    super()
    this._service = service
  }

  async execute() {
    const userEntity = await this._service.execute()
    return userEntity.toJSON()
  }
}
import {Service} from '@s-ui/domain'

export default class CurrentUserService extends Service {
  constructor({repository} = {}) {
    super()
    this._repository = repository
  }

  async execute() {
    const userEntity = this._repository.current()
    return userEntity
  }
}

Listen a useCase

@s-ui/domain includes a way to subscribe to every useCase execution without the need of using any kind of decorator or external dependency.

This is useful if you have side effects in a different place from where you're executing the useCase of the domain.

domain
  .get('generate_search_url_search_use_case')
  .subscribe(({params, error, result}) => {
    // doSomething when the useCase generate_search_url_search_use_case is called in other place
  })

If you want unsubscribe any useCase execution

const subscribedUseCase$ = domain
  .get('generate_search_url_search_use_case')
  .subscribe(({params, error, result}) => {
    // doSomething when the useCase generate_search_url_search_use_case is called in other place
  })

subscribedUseCase$.unsubscribe()