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

@ignitial/iio-services

v2.5.3

Published

Ignitial.io microservices

Downloads

113

Readme

IgnitialIO Services (IIOS)

WARNING !

IIOS v2 is not compliant with IIOS v1

Micro-services framework. Base brick for IgnitialIO toolbox that aims to provide everything needed to build resilient complex systems based on web technologies.

It is:

  • cloud ready: naturally works with Docker, Kubernetes etc.
  • edge/embedded computing ready: provide a cloud extension deploying micro-services within a data center, as well as on embedded or edge targets
  • simple, reliable, easy to maintain (~ 1600 SLOCs)
  • production ready: well tested, easy to deploy, easy to use
  • in one word, resilient: few mandatory dependecies, works with Redis, but can replace Redis with any KV store + pub/sub broker, manages complexity with simple solutions

Main features:

  • namespaced micro-services
  • RPC based services intercall (~ 5000 calls/sec on i7 8th generation - one core used)
  • HTTP backup services intercall (can work without KV store + pub/sub broker)
  • inter-services streaming (data pipes, etc.)
  • inter-services events
  • maps any service methods to any gateway with a given namespace
  • distributed Role Based Access Control
  • UI injection (if used in the IgnitialIO web app framework context)
  • workflow ready with inter-services functions, events and stream binding

Get started

Any service can call any other. In order to do so, caller has to be a gateway which is a special service that offers an API for calling remote services:

Gateway side:

const Gateway = require('@ignitial/iio-services').Gateway
const config = require('./config')

let gateway = new Gateway(config)

gateway._init().then(() => {  
  gateway._waitForService('bob').then(serviceInfo => {
    console.log(serviceInfo)

    gateway.api.bob.bobAwesomeMethod(p1, p2, { $userId: <ifany> }).then(response => {
      console.log(response)
    }).catch(err => console.log('service failed with err', err))
}).catch(err) {...}

Service side:

const Service = require('../../').Service

class Bob extends Service {
  constructor(options) {
    super(options)
  }

  bobAwesomeMethod(p1, p2, userId) {
    /* @_GET_ */
    return new Promise((resolve, reject) => {
      resolve('got ' + p1 + ', ' + p2)
    })
  }
}

let bob = new Bob(config)
bob._init().then(() => { }).catch(err => {})

Inter-services events

Subscriber side:

gateway._init().then(() => {  
  // given event fro given service
  gateway.on('iios:bob:event:coucou', data => {
    console.log(data) // effective payload == data
  })

  // or any event from a given service
  gateway.on('iios:bob:event', message => {
    console.log(message.meta) // message meta information
    console.log(message.payload) // effective payload == data
  })

  // or any event from any service
  gateway.on('iios:event', data => {
    console.log(message.meta) // message meta information
    console.log(message.payload) // effective payload == data
  })
}).catch(err) {...}

Publisher side:

let bob = new Bob(config)
bob._init().then(() => {
  bob._pushEvent('coucou', { toto: 'titi' })
}).catch(err => {})

Methods declaration

Any class method declared without '_' or '$' characters as first one in the name and different from reserved methods (mainly NodeJS EventEmitter's public méthods) are automatically callable once service initialized.

An additional info (here: /* @GET */) can be provided to tel the service that refered method is one of get, put, post or delete HTTP call types.

By default, is considered as post, but not available to HTTP backup API. This means that a method for which no information has been provided, cannot be called through HTTP API mechanism, but only through pub/sub using the broker if available.

Service options

Options example:

{  
  /* service name */
  name: 'alice',
  /* eventually disables pub/sub calling mechanism in order to use only HTTP */
  kvStoreMode: process.env.KV_STORE_MODE,
  /* discovery servers (gateways) when HTTP only */
  discoveryServers: [],
  /* calling timeout for pub/sub mode */
  timeout: 500,
  /* metrics configuration: no metrics if undefined */
  metrics: {
    /* number of points that triggers metrics push event */
    pushTrigger: 100,
    /* maw number of points to store locally */
    maxPoints: 100
  },
  /* PUB/SUB/KV connector */
  connector: {
    /* redis server connection */
    redis: {
      /* encoder to be used for packing/unpacking raw messages */
      encoder: process.env.ENCODER || 'json',
      /* redis host ip or hostname */
      host: process.env.REDIS_HOST,
      /* if redis sentinel enabled, master name */
      master: process.env.REDIS_MASTER_NAME,
      /* uses redis sentinel if defined */
      sentinels: REDIS_SENTINELS,
      /* redis port */
      port: 6379,
      /* redis db number */
      db: 0,
      /* ip family */
      ipFamily: 4
    }
  },
  /* access control: if present, acces control enabled */
  accesscontrol: {
    /* grants for current service: auto-fill */
    grants: {
      admin: {
        'create:any': [ '*' ],
        'read:any': [ '*' ],
        'update:any': [ '*' ],
        'delete:any': [ '*' ]
      },
      user: {
        'read:any': [ '*' ],
        'update:any': [ '*' ],
        'delete:any': [ '*' ]
      },
      anonymous: {
        'read:any': [ '*' ]
      }
    },
    /* access control namespace */
    namespace: process.env.IIOS_NAMESPACE || 'iios',
    /* connector configuration: optional, default same as global connector, but
       on DB 1 */
    connector: {
      /* redis server connection */
      redis: {
        host: process.env.REDIS_HOST,
        port: 6379,
        db: 1,
        ipFamily: 4
      }
    }
  },
  /* service namesapce */
  namespace: process.env.IIOS_NAMESPACE || 'iios',
  /* HTTP server declaration */
  server: {
    /* server host for external call */
    host: process.env.IIOS_SERVER_HOST,
    /* server port */
    port: process.env.IIOS_SERVER_PORT,
    /* indicates that service is behind an HTTPS proxy */
    https: false,
    /* path to statically serve (at least one asset for icons for example) */
    path: './dist'
  },
  /* options published through discovery mechanism */
  publicOptions: {}
}

Access control

If option is activated, any call will have to get clearence from a local access control mechanism based on roles stored in the KV store.

Each user id has a corresponding role. No user id means anonymous role.

Services use user id and not tokens, since tokens have to enforce auth and access control only at the web app level.

A typical access control definition would be:

admin: {
  'bob': {
    'create:any': [ '*' ],
    'read:any': [ '*' ],
    'update:any': [ '*' ],
    'delete:any': [ '*' ]
  },
  ...
}

which means that role admin can:

  • create:any === make PUT calls
  • read:any === make GET calls
  • update:any === make POST calls
  • delete:any === make DELETE calls to the service bob.

Tests

Lint

npm run lint

Prepare test image (mandatory)

npm run config:build

Prepare users and access control data (mandatory)

npm run config:populate

Access control

npm run test:accesscontrol

Service

Tests basique service features.

npm run test:service

Services

Tests service call from gateway using pub/sub primary mechanism.

npm run test:services

Services in HTTP mode

Tests service call from gateway using HTTP backup mechanism.

npm run test:services:http

Streaming

Tests service streaming.

npm run test:streams