A microservices toolkit for Node.js.

Overview

Logo

A Node.js toolkit for Microservice architectures

Voxgig This open source module is sponsored and supported by Voxgig.

seneca

Npm NpmFigs Travis Coveralls DeepScan CodeClimate Gitter

Seneca is a toolkit for writing microservices and organizing the business logic of your app. You can break down your app into "stuff that happens", rather than focusing on data models or managing dependencies.

Seneca provides,

  • pattern matching: a wonderfully flexible way to handle business requirements

  • transport independence: how messages get to the right server is not something you should have to worry about

  • maturity: 8 years in production (before we called it microservices), but was once taken out by lightning

  • plus: a deep and wide ecosystem of plugins

  • book: a guide to designing microservice architectures: taomicro

Use this module to define commands that work by taking in some JSON, and, optionally, returning some JSON. The command to run is selected by pattern-matching on the the input JSON. There are built-in and optional sets of commands that help you build Minimum Viable Products: data storage, user management, distributed logic, caching, logging, etc. And you can define your own product by breaking it into a set of commands - "stuff that happens". That's pretty much it.

If you're using this module, and need help, you can:

If you are new to Seneca in general, please take a look at senecajs.org. We have everything from tutorials to sample apps to help get you up and running quickly.

Seneca's source can be read in an annotated fashion by running npm run annotate. An annotated version of each file will be generated in ./docs/.

Install

To install via npm,

npm install seneca

Quick Example

'use strict'

var Seneca = require('seneca')


// Functionality in seneca is composed into simple
// plugins that can be loaded into seneca instances.


function rejector () {
  this.add('cmd:run', (msg, done) => {
    return done(null, {tag: 'rejector'})
  })
}

function approver () {
  this.add('cmd:run', (msg, done) => {
    return done(null, {tag: 'approver'})
  })
}

function local () {
  this.add('cmd:run', function (msg, done) {
    this.prior(msg, (err, reply) => {
      return done(null, {tag: reply ? reply.tag : 'local'})
    })
  })
}


// Services can listen for messages using a variety of
// transports. In process and http are included by default.


Seneca()
  .use(approver)
  .listen({type: 'http', port: '8260', pin: 'cmd:*'})

Seneca()
  .use(rejector)
  .listen(8270)


// Load order is important, messages can be routed
// to other services or handled locally. Pins are
// basically filters over messages


function handler (err, reply) {
  console.log(err, reply)
}

Seneca()
  .use(local)
  .act('cmd:run', handler)

Seneca()
  .client({port: 8270, pin: 'cmd:run'})
  .client({port: 8260, pin: 'cmd:run'})
  .use(local)
  .act('cmd:run', handler)

Seneca()
  .client({port: 8260, pin: 'cmd:run'})
  .client({port: 8270, pin: 'cmd:run'})
  .use(local)
  .act('cmd:run', handler)


// Output
// null { tag: 'local' }
// null { tag: 'approver' }
// null { tag: 'rejector' }

Running

To run normally, say in a container, use

$ node microservice.js

(where microservice.js is a script file that uses Seneca). Logs are output in JSON format so you can send them to a logging service.

To run in test mode, with human-readable, full debug logs, use:

$ node microservice.js --seneca.test

Why we built this?

So that it doesn't matter,

  • who provides the functionality,
  • where it lives (on the network),
  • what it depends on,
  • it's easy to define blocks of functionality (plugins!).

So long as some command can handle a given JSON document, you're good.

Here's an example:

var seneca = require('seneca')()

seneca.add({cmd: 'salestax'}, function (msg, done) {
  var rate  = 0.23
  var total = msg.net * (1 + rate)
  done(null, {total: total})
})

seneca.act({cmd: 'salestax', net: 100}, function (err, result) {
  console.log(result.total)
})

In this code, whenever seneca sees the pattern {cmd:'salestax'}, it executes the function associated with this pattern, which calculates sales tax. There is nothing special about the property cmd . It is simply the property we want to pattern match. You could look for foo for all seneca cares! Yah!

The seneca.add method adds a new pattern, and the function to execute whenever that pattern occurs.

The seneca.act method accepts an object, and runs the command, if any, that matches.

Where does the sales tax rate come from? Let's try it again:

seneca.add({cmd: 'config'}, function (msg, done) {
  var config = {rate: 0.23}
  var value = config[msg.prop]
  done(null, {value: value})
})

seneca.add({cmd: 'salestax'}, function (msg, done) {
  seneca.act({cmd: 'config', prop: 'rate'}, function (err, result) {
    var rate  = parseFloat(result.value)
    var total = msg.net * (1 + rate)
    done(null, {total: total})
  })
})

seneca.act({cmd: 'salestax', net: 100}, function (err, result) {
  console.log(result.total)
})

The config command provides you with your configuration. This is cool because it doesn't matter where it gets the configuration from - hard-coded, file system, database, network service, whatever. Did you have to define an abstraction API to make this work? Nope.

There's a little but too much verbosity here, don't you think? Let's fix that:

seneca.act('cmd:salestax,net:100', function (err, result) {
  console.log(result.total)
})

Instead of providing an object, you can provide a string using an abbreviated form of JSON. In fact, you can provide both:

seneca.act('cmd:salestax', {net: 100}, function (err, result) {
  console.log(result.total)
})

This is a very convenient way of combining a pattern and parameter data.

Programmer Anarchy

The way to build Node.js systems, is to build lots of little processes. Here's a great talk explaining why you should do this: Programmer Anarchy.

Seneca makes this really easy. Let's put configuration out on the network into its own process:

seneca.add({cmd: 'config'}, function (msg, done) {
  var config = {rate: 0.23}
  var value = config[msg.prop]
  done(null, { value: value })
})

seneca.listen()

The listen method starts a web server that listens for JSON messages. When these arrive, they are submitted to the local Seneca instance, and executed as actions in the normal way. The result is then returned to the client as the response to the HTTP request. Seneca can also listen for actions via a message bus.

Your implementation of the configuration code stays the same.

The client code looks like this:

seneca.add({cmd: 'salestax'}, function (msg, done) {
  seneca.act({cmd: 'config', prop: 'rate' }, function (err, result) {
    var rate  = parseFloat(result.value)
    var total = msg.net * (1 + rate)
    done(null, { total: total })
  })
})

seneca.client()

seneca.act('cmd:salestax,net:100', function (err, result) {
  console.log(result.total)
})

On the client-side, calling seneca.client() means that Seneca will send any actions it cannot match locally out over the network. In this case, the configuration server will match the cmd:config pattern and return the configuration data.

Again, notice that your sales tax code does not change. It does not need to know where the configuration comes from, who provides it, or how.

You can do this with every command.

Keeping the Business Happy

The thing about business requirements is that they have no respect for common sense, logic or orderly structure. The real world is messy.

In our example, let's say some countries have single sales tax rate, and others have a variable rate, which depends either on locality, or product category.

Here's the code. We'll rip out the configuration code for this example.

// fixed rate
seneca.add({cmd: 'salestax'}, function (msg, done) {
  var rate  = 0.23
  var total = msg.net * (1 + rate)
  done(null, { total: total })
})


// local rates
seneca.add({cmd: 'salestax', country: 'US'}, function (msg, done) {
  var state = {
    'NY': 0.04,
    'CA': 0.0625
    // ...
  }
  var rate = state[msg.state]
  var total = msg.net * (1 + rate)
  done(null, {total: total})
})


// categories
seneca.add({ cmd: 'salestax', country: 'IE' }, function (msg, done) {
  var category = {
    'top': 0.23,
    'reduced': 0.135
    // ...
  }
  var rate = category[msg.category]
  var total = msg.net * (1 + rate)
  done(null, { total: total })
})


seneca.act('cmd:salestax,net:100,country:DE', function (err, result) {
  console.log('DE: ' + result.total)
})

seneca.act('cmd:salestax,net:100,country:US,state:NY', function (err, result) {
  console.log('US,NY: ' + result.total)
})

seneca.act('cmd:salestax,net:100,country:IE,category:reduced', function (err, result) {
  console.log('IE: ' + result.total)
})

In this case, you provide different implementations for different patterns. This lets you isolate complexity into well-defined places. It also means you can deal with special cases very easily.

Contributing

The Senecajs org encourages participation. If you feel you can help in any way, be it with bug reporting, documentation, examples, extra testing, or new features feel free to create an issue, or better yet, submit a Pull Request. For more information on contribution please see our Contributing guide.

Test

To run tests locally,

npm run test

To obtain a coverage report,

npm run coverage; open docs/coverage.html

License

Copyright (c) 2010-2018 Richard Rodger and other contributors; Licensed under MIT.

Comments
  • Promise support for common API

    Promise support for common API

    Hi,

    When I experiments with Seneca, I found two much callback needed especially about data entity.

    Promise is a very good way to improve callback hell and provide robust error handling mechanism.

    What about adding promise support for seneca.act and data entity api like save$/load$ and so on?

    Trello Card

    opened by oliverzy 43
  • client repeats first

    client repeats first "acted" message when service-process restarts

    i have a strange issue. i have built a service (listening on a tcp port) and a client which connects to the service. i can add methods to the service and act them from the client. everything fine so far. but everytime i restart the service-process it receives the first "acted" method (since client-process started) from the client again and executes it. after restarting the client-process the service does not receive messages when it is restarted. but after the first act-call on the client, the service-process receives the first "acted" message again. any ideas?

    service.js

    'use strict';
    
    var seneca = require('seneca');
    
    var service = seneca();
    
    service.add({
        role: 'foo',
        cmd: 'bar'
    }, function(args, cb) {
        console.log(args.name, Date.now(), args.meta$.id);
        cb(null, { test:123, name: args.name });
    } )
    
    
    service.listen({
        type: 'tcp',
        port: 12345,
        host: '0.0.0.0'
    });
    
    

    client.js

    'use strict';
    
    var seneca = require('seneca');
    
    var service = seneca();
    
    service.client({
        type: 'tcp',
        port: 12345,
        host: '0.0.0.0',
        pin: 'role:foo'
    });
    
    
    service.act({
        role: 'foo',
        cmd: 'bar',
        name: 'tobi',
    }, function(err, res) {
        console.log(res, Date.now());
    });
    
    • start service.js

    • start client.js

      client logs: { test: 123, name: 'tobi' } 1453365970625 service logs: tobi 1453365970622 bl7z8vtfzapr/pu6z54yliflt

    • stop service.js

    • start service.js

      client logs: { test: 123, name: 'tobi' } 1453366057821 service logs: tobi 1453366057818 bl7z8vtfzapr/pu6z54yliflt

    https://github.com/platdesign/seneca-issue

    opened by platdesign 41
  • Error handling and bootstrap refactor

    Error handling and bootstrap refactor

    See the discussion in https://github.com/senecajs/seneca/issues/398.

    Seneca-transport needs the same treatment, coming soon.

    If we decide to merge this, we might want to do a 3.x prerelease, to start checking all the applications and plugins.

    cc @pelger @davidmarkclements @mcdonnelldean @AdrianRossouw @rjrodger.

    opened by mcollina 34
  • Proposition for a documentation standard for plugins and actions

    Proposition for a documentation standard for plugins and actions

    To help adoption and learning of seneca, documentation of the API: plugin and actions is crucial.

    And one of the current goal of senecajs: https://github.com/senecajs/senecajs.org/issues/65 Here a proposition of this could be done, relying on [jsdoc]{http://usejsdoc.org/):

    User friendly documentation would be then generated from it, to be available on seneca website. (and other doc browser)

    Format

    plugin

    /**
     * My Seneca Plugin
     *
     * @module pluginName
     * @param {Object} options - Plugin options 
     * @param {String} options.hello - Person to greet
     *
     * @returns {string} the plugin name
     */
    module.exports = function (options) {}
    

    actions

    The action should be documentated on the name of the handler.

      /**
       * @callback pluginActionCallback
       * @param {Object} error - error that occured
       * @param {Object} result - result of call
       * @param {String} result.greeting - the greeting
       */
    
      /**
       * Hello Action
       *
       * @param {Object} msg - Message option
       * @param {String} msg.hello -  Person to greet
       *
       * @param {pluginActionCallback} respond - callback
       */
      function hello(msg, respond) {
    

    Exemple

    Here is what it could look like in practice: https://github.com/AdrieanKhisbe/seneca-cron/blob/documentation-proposal/lib/cron.js

    Discussion

    Feedback are much welcome, this is just a starter for discussion.

    @rjrodger @mcollina @mcdonnelldean @geek

    opened by AdrieanKhisbe 34
  • Global timeout not firing on 3.2.1

    Global timeout not firing on 3.2.1

    @mcdonnelldean Hi, guys! So, today @vigneshnrfs opened an issue over at seneca-amqp-transport explaining that his actions weren't timeoutting using latest Seneca release 3.0.0, but were doing fine in 2.1.0. It turned out he was (is) absolutely right.

    I investigated a little bit and found out that some work has been done on this. Like doubling the default timeout value. Has any of the API changed regarding this? Would you have any ideas on why no TIMEOUT errors are being thrown on Seneca 3.0.0? Maybe I need to update something on the transport logic?

    Thanks!

    opened by nfantone 28
  • Logging Rethink

    Logging Rethink

    Logging needs a rethink, my thoughts.

    • Contain a lot of unneeded information.
    • Don't capture highly valuable internal information and stats
    • Are not json based
    • Have truncation errors meaning they are lossy
    • Aren't easily pipable

    In terms of logging, I would love to get a week of @mcollina's time to bring in pino. Pino is wicked fast and has sub loggers which dovetails perfectly with our plugin structure. I'd love to see a spike with three key goals

    • Bring in pino, and sub logging for plugins
    • Rework core stats and information output
    • Provide a proxy for old logging so we don't break the universe

    A spike could at least give us something to discuss. Nodezoo is a great system to play around with logging since you can run each service in isolated mode and manipulate it via curl or postman.

    Contributors and users, please feel free to add pain points and constructive feedback.

    Agreed Detail

    Feel free to correct in an issue below

    • Logging will object based
    • Loggers will need to be api compatible with bunyan / pino
    • An adapter will need to be provided for libs like Winston, etc
    opened by mcdonnelldean 28
  • Seneca actions and plugins do not support => functions.

    Seneca actions and plugins do not support => functions.

    The way that we currently register callbacks with seneca is not forward compatible with ES6.

    The problem is thus :

    seneca.add('role:x,cmd:y', (args, done) => {
      let seneca = this; // this won't work any longer.
    });
    

    The only thing I can think of is to explicitly pass in the seneca instance as the first argument, which would break the function signature and all existing seneca code :

    seneca.add('role:x,cmd:y', (sen, args, done) => {
       // no more this;  
    });
    

    The one trick that we could have used was checking arity with function.length, but I think that becomes much less reliable with default and ...rest parameters, and would lead to strange and hard to debug errors.

    opened by AdrianRossouw 23
  • 3.0 Test and Repo Pretidy

    3.0 Test and Repo Pretidy

    This is an effort to tidy the test suite and related structure before 3.0 launches.

    Changes

    • Removed remaining legacy logging artefacts. Logging is now complete.
    • Removed all dead code from the test suite,
    • Removed unused stubs from the test suite,
    • Removed code which didn't run from test suite,
    • Removed samples that used features that have been deprecated.
    • Corrected code conventions in the README to use msg/done format.
    • Moved coverage file to /docs
    • Corrected names of various files and examples in /docs
    • Flattened test structure so all *.test.js files are in root test folder
    • options.tests.js is the exception as it needs rework to be moved
    • Moved all stubs being used into stubs folder for readability purposes
    • Added a high value example to the README to show off more features
    • Removed seneca echo tests and dev depencency (since it's not default)
    • Removed unused dependency for eslint
    • Removed Repl tests as they are to be moved to seneca-repl
    • Removed all manual testing files in preperation for auto testing via 'The Rig'

    @rjrodger You may want to throw an eye over this. Bear in mind two points. We are going to be testing all SenecaJs plugins via The Rig post 3.0 and we are fixing documentation so are looking to remove all of the out of date examples from the repos.

    opened by mcdonnelldean 18
  • Create declaration files for TypeScript

    Create declaration files for TypeScript

    I use TypeScript, and seneca has a fairly complex interface, so I want TypeScript declaration files following best practices.

    I will start on these, and add to them as I learn the details of the interface, and while the API docs are being updated, see https://github.com/rjrodger/seneca/issues/155

    opened by psnider 18
  • client.act seems to fail when the input contains cmd: 'get'

    client.act seems to fail when the input contains cmd: 'get'

    This behavior started with 1.4.0.

    Repro:

    'use strict';
    
    const service = require('seneca')();
    
    const inputs = [
        { cmd: 'create' },
        { cmd: 'get' },
        { role: 'test', cmd: 'get' },
        { ball: 'get' },
        { dog: 'get' },
        { thing: 'get' },
        { cmd: 'update' }
    ];
    
    inputs.forEach((input) => {
    
        service.add(input, (args, respond) => {
    
            respond(null, { input });
        });
    });
    
    service.listen();
    
    service.ready(function (err) {
    
        if (err) return;
    
        const client = require('seneca')().client();
    
        inputs.forEach((input) => {
    
            service.act(input, (err, result) => console.log(err  && `👎  (service.act) ${err}` || `👍  (service.act) ${JSON.stringify(result)}`));
            client.act(input, (err, result) => console.log(err  && `👎  (client.act) ${err}` || `👍  (client.act) ${JSON.stringify(result)}`));
        });
    
        setTimeout(() => service.close((err) => process.exit()), 1000);
    });
    

    Expected output (via 1.3.0):

    2016-03-18T12:49:34.165Z nu8mey7bb8az/1458305374148/21387/- INFO    hello   Seneca/1.3.0/nu8mey7bb8az/1458305374148/21387/-
    2016-03-18T12:49:34.451Z nu8mey7bb8az/1458305374148/21387/- INFO    listen
    2016-03-18T12:49:34.539Z i0qppq7gufyj/1458305374536/21387/- INFO    hello   Seneca/1.3.0/i0qppq7gufyj/1458305374536/21387/-
    2016-03-18T12:49:34.543Z i0qppq7gufyj/1458305374536/21387/- INFO    client
    👍  (service.act) {"input":{"cmd":"create"}}
    👍  (service.act) {"input":{"cmd":"get"}}
    👍  (service.act) {"input":{"role":"test","cmd":"get"}}
    👍  (service.act) {"input":{"ball":"get"}}
    👍  (service.act) {"input":{"dog":"get"}}
    👍  (service.act) {"input":{"thing":"get"}}
    👍  (service.act) {"input":{"cmd":"update"}}
    👍  (client.act) {"input":{"cmd":"create"}}
    👍  (client.act) {"input":{"cmd":"get"}}
    👍  (client.act) {"input":{"role":"test","cmd":"get"}}
    👍  (client.act) {"input":{"ball":"get"}}
    👍  (client.act) {"input":{"dog":"get"}}
    👍  (client.act) {"input":{"thing":"get"}}
    👍  (client.act) {"input":{"cmd":"update"}}
    

    1.4.0 output:

    2016-03-18T12:53:09.526Z tfpiuy2nfhrm/1458305589510/21555/- INFO    hello   Seneca/1.4.0/tfpiuy2nfhrm/1458305589510/21555/-
    2016-03-18T12:53:09.792Z tfpiuy2nfhrm/1458305589510/21555/- INFO    listen
    2016-03-18T12:53:09.877Z x0lerjt7ummy/1458305589875/21555/- INFO    hello   Seneca/1.4.0/x0lerjt7ummy/1458305589875/21555/-
    2016-03-18T12:53:09.882Z x0lerjt7ummy/1458305589875/21555/- INFO    client
    👍  (service.act) {"input":{"cmd":"create"}}
    👍  (service.act) {"input":{"cmd":"get"}}
    👍  (service.act) {"input":{"role":"test","cmd":"get"}}
    👍  (service.act) {"input":{"ball":"get"}}
    👍  (service.act) {"input":{"dog":"get"}}
    👍  (service.act) {"input":{"thing":"get"}}
    👍  (service.act) {"input":{"cmd":"update"}}
    2016-03-18T12:53:09.946Z x0lerjt7ummy/1458305589875/21555/- WARN    act -           -   -   seneca: No matching action pattern found for { cmd: 'get' }, and no default result provided (using a default$ property).    act_not_found   {args:{ cmd: 'get' },plugin:{}} Error: seneca: No matching action pattern found for { cmd: 'get' }, and no default result provided (using a default$ property).
        at Object.errormaker [as error] (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/node_modules/eraro/eraro.js:94:15)
        at Object.execute_action [as fn] (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/seneca.js:1090:25)
        at Immediate._onImmediate (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/node_modules/gate-executor/gate-executor.js:136:14)
        at processImmediate [as _immediateCallback] (timers.js:383:17)
    2016-03-18T12:53:09.947Z x0lerjt7ummy/1458305589875/21555/- ERROR   act -           OUT     -   63  {cmd:get}   ENTRY       -   seneca: No matching action pattern found for { cmd: 'get' }, and no default result provided (using a default$ property).    act_not_found   {args:{ cmd: 'get' },plugin:{}} Error: seneca: No matching action pattern found for { cmd: 'get' }, and no default result provided (using a default$ property).
        at Object.errormaker [as error] (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/node_modules/eraro/eraro.js:94:15)
        at Object.execute_action [as fn] (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/seneca.js:1090:25)
        at Immediate._onImmediate (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/node_modules/gate-executor/gate-executor.js:136:14)
        at processImmediate [as _immediateCallback] (timers.js:383:17)
    👎  (client.act) Error: seneca: No matching action pattern found for { cmd: 'get' }, and no default result provided (using a default$ property).
    2016-03-18T12:53:09.948Z x0lerjt7ummy/1458305589875/21555/- WARN    act -           -   -   seneca: No matching action pattern found for { role: 'test', cmd: 'get' }, and no default result provided (using a default$ property).  act_not_found   {args:{ role: 'test', cmd: 'get' },plugin:{}}   Error: seneca: No matching action pattern found for { role: 'test', cmd: 'get' }, and no default result provided (using a default$ property).
        at Object.errormaker [as error] (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/node_modules/eraro/eraro.js:94:15)
        at Object.execute_action [as fn] (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/seneca.js:1090:25)
        at Immediate._onImmediate (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/node_modules/gate-executor/gate-executor.js:136:14)
        at processImmediate [as _immediateCallback] (timers.js:383:17)
    2016-03-18T12:53:09.948Z x0lerjt7ummy/1458305589875/21555/- ERROR   act -           OUT     -   64  {role:test,cmd:get} ENTRY       -   seneca: No matching action pattern found for { role: 'test', cmd: 'get' }, and no default result provided (using a default$ property).  act_not_found   {args:{ role: 'test', cmd: 'get' },plugin:{}}   Error: seneca: No matching action pattern found for { role: 'test', cmd: 'get' }, and no default result provided (using a default$ property).
        at Object.errormaker [as error] (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/node_modules/eraro/eraro.js:94:15)
        at Object.execute_action [as fn] (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/seneca.js:1090:25)
        at Immediate._onImmediate (/Users/heskew/src/nearform/tmp/seneca-tmp/node_modules/seneca/node_modules/gate-executor/gate-executor.js:136:14)
        at processImmediate [as _immediateCallback] (timers.js:383:17)
    👎  (client.act) Error: seneca: No matching action pattern found for { role: 'test', cmd: 'get' }, and no default result provided (using a default$ property).
    👍  (client.act) {"input":{"cmd":"create"}}
    👍  (client.act) {"input":{"ball":"get"}}
    👍  (client.act) {"input":{"dog":"get"}}
    👍  (client.act) {"input":{"thing":"get"}}
    👍  (client.act) {"input":{"cmd":"update"}}
    
    opened by heskew 17
  • seneca catch error that should be catched by mocha

    seneca catch error that should be catched by mocha

    I'm not sure if that is the same issue as seneca catching 'uncaught exceptions' but I have a test with 'asserts'. I'd expect the tests to fail with an error for which the stack top level line is where the assert line is, not in seneca's internals.

    The test (edited):

    describe('archive', function() {
    
      it('save', function(done) {
    
        var foobarEntity = primarySeneca.make('foo/bar')
    
        foobarEntity.save$({db: 'primary', archiveAttr: false}, function(err, result) {
    
          assert.ok(!err, err ? err.message + err.stack : undefined)
    
          foobarEntity.save$({db: 'secondary', archiveAttr: true}, function(err, secondaryResult) {
            assert.ok(!err, err ? err.message + err.stack : undefined)
    
    
            var foobarEntitySecondary = secondarySeneca.make('foo/bar')
            foobarEntitySecondary.load$({id: secondaryResult.id}, function(err, archivedEntity) {
    
              assert.ok(!err, err ? err.message + err.stack : undefined)
              assert.ok(archivedEntity)
              assert.equal(archivedEntity.id, secondaryResult.id)     
    
              done()     
    
            })
    
          })
    
        })
    
      })
    })
    

    The logs:

    2014-05-13T15:34:23.120Z    ERROR   act err 0ptr7z  callback    Seneca/0.5.17/xauigd: {name=AssertionError,actual=,expected=true,operator===,message=null == true}  botzgv      at Seneca.<anonymous> (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/mem-store.js:133:9)
        1) save
        ✓ list 
    
    
      12 passing (18ms)
      1 failing
    
      1) archive save:
         Error: Seneca/0.5.17/xauigd: {name=AssertionError,actual=,expected=true,operator===,message=null == true}
          at act_done (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1529:25)
          at Seneca.<anonymous> (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/mem-store.js:133:9)
          at list (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/mem-store.js:55:6)
          at Seneca.store.load (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/mem-store.js:130:7)
          at perform (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1551:22)
          at do_act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1422:17)
          at Seneca.api_act [as act] (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1255:10)
          at Entity.load$ (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/entity.js:192:6)
          at Seneca.<anonymous> (/Users/nherment/workspace/seneca-archive/test/archive.test.js:37:31)
          at act_done (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1516:16)
          at Seneca.<anonymous> (/Users/nherment/workspace/seneca-archive/archive.js:119:9)
          at act_done (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1516:16)
          at do_save (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/mem-store.js:121:9)
          at Seneca.<anonymous> (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/mem-store.js:100:13)
          at act_done (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1516:16)
          at Seneca.cmd_generate_id (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/util.js:85:5)
          at perform (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1551:22)
          at do_act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1422:17)
          at Seneca.api_act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1255:10)
          at Seneca.delegate.act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1825:11)
          at Seneca.delegate.act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1825:11)
          at Seneca.store.save (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/mem-store.js:98:16)
          at perform (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1551:22)
          at do_act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1422:17)
          at Seneca.delegate.prior.delegate.parent (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1458:13)
          at Seneca.executePrimaryThenFallbackToSecondary (/Users/nherment/workspace/seneca-archive/archive.js:108:10)
          at Seneca.saveOverride (/Users/nherment/workspace/seneca-archive/archive.js:42:45)
          at perform (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1551:22)
          at do_act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1422:17)
          at Seneca.api_act [as act] (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1255:10)
          at Entity.save$ (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/entity.js:160:6)
          at Seneca.<anonymous> (/Users/nherment/workspace/seneca-archive/test/archive.test.js:32:20)
          at act_done (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1516:16)
          at Seneca.<anonymous> (/Users/nherment/workspace/seneca-archive/archive.js:119:9)
          at act_done (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1516:16)
          at do_save (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/mem-store.js:121:9)
          at Seneca.<anonymous> (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/mem-store.js:100:13)
          at act_done (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1516:16)
          at Seneca.cmd_generate_id (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/util.js:85:5)
          at perform (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1551:22)
          at do_act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1422:17)
          at Seneca.api_act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1255:10)
          at Seneca.delegate.act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1825:11)
          at Seneca.delegate.act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1825:11)
          at Seneca.store.save (/Users/nherment/workspace/seneca-archive/node_modules/seneca/plugin/mem-store.js:98:16)
          at perform (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1551:22)
          at do_act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1422:17)
          at Seneca.delegate.prior.delegate.parent (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1458:13)
          at Seneca.executePrimaryThenFallbackToSecondary (/Users/nherment/workspace/seneca-archive/archive.js:108:10)
          at Seneca.saveOverride (/Users/nherment/workspace/seneca-archive/archive.js:42:45)
          at perform (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1551:22)
          at do_act (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1422:17)
          at Seneca.api_act [as act] (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/seneca.js:1255:10)
          at Entity.save$ (/Users/nherment/workspace/seneca-archive/node_modules/seneca/lib/entity.js:160:6)
          at Context.<anonymous> (/Users/nherment/workspace/seneca-archive/test/archive.test.js:28:18)
          at Test.Runnable.run (/Users/nherment/workspace/seneca-archive/node_modules/mocha/lib/runnable.js:196:15)
          at Runner.runTest (/Users/nherment/workspace/seneca-archive/node_modules/mocha/lib/runner.js:374:10)
          at /Users/nherment/workspace/seneca-archive/node_modules/mocha/lib/runner.js:452:12
          at next (/Users/nherment/workspace/seneca-archive/node_modules/mocha/lib/runner.js:299:14)
          at /Users/nherment/workspace/seneca-archive/node_modules/mocha/lib/runner.js:309:7
          at next (/Users/nherment/workspace/seneca-archive/node_modules/mocha/lib/runner.js:247:23)
          at Object._onImmediate (/Users/nherment/workspace/seneca-archive/node_modules/mocha/lib/runner.js:276:5)
          at processImmediate [as _immediateCallback] (timers.js:330:15)
    

    Trello Card

    opened by nherment 16
  • Plugin namespace conflict

    Plugin namespace conflict

    When using the debug plugin, it's namespace will conflict with seneca definition types and it's configuration parameters will get inject with new parameters.

    Seneca debug namespace:

    debug?: {
          // Throw (some) errors from seneca.act.
          fragile?:    boolean | undefined;
          // Fatal errors ... aren't fatal. Not for production!
          undead?:     boolean | undefined;
          // Print debug info to console
          print?: {
              // Print options. Best used via --seneca.print.options.
              options?: boolean | undefined;
          } | undefined;
          // Trace action caller and place in args.caller$.
          act_caller?: boolean | undefined;
          // Shorten all identifiers to 2 characters.
          short_logs?: boolean | undefined;
          // Record and log callpoints (calling code locations).
          callpoint?: boolean | undefined;
      } | undefined;
    

    Those parameters will get injected in the debug config parameters if you boot it like this:

    seneca.use('debug', { ...myParams })

    opened by vitorclelis96 0
  • [Snyk] Security upgrade body-parser from 1.19.0 to 1.19.2

    [Snyk] Security upgrade body-parser from 1.19.0 to 1.19.2

    This PR was automatically created by Snyk using the credentials of a real user.


    Snyk has created this PR to fix one or more vulnerable packages in the `npm` dependencies of this project.

    Changes included in this PR

    • Changes to the following files to upgrade the vulnerable dependencies to a fixed version:
      • docs/examples/sales-tax/package.json
      • docs/examples/sales-tax/package-lock.json

    Vulnerabilities that will be fixed

    With an upgrade:

    Severity | Priority Score (*) | Issue | Breaking Change | Exploit Maturity :-------------------------:|-------------------------|:-------------------------|:-------------------------|:------------------------- high severity | 768/1000
    Why? Proof of Concept exploit, Recently disclosed, Has a fix available, CVSS 7.5 | Prototype Pollution
    SNYK-JS-QS-3153490 | No | Proof of Concept

    (*) Note that the real score may have changed since the PR was raised.

    Commit messages
    Package name: body-parser The new version differs by 101 commits.

    See the full diff

    Check the changes in this PR to ensure they won't cause issues with your project.


    Note: You are seeing this because you or someone else with access to this repository has authorized Snyk to open fix PRs.

    For more information: 🧐 View latest project report

    🛠 Adjust project settings

    📚 Read more about Snyk's upgrade and patch logic


    Learn how to fix vulnerabilities with free interactive lessons:

    🦉 Prototype Pollution

    opened by rjrodger 1
  • plugin loading when$ directive

    plugin loading when$ directive

    if when$ evaluates to false, don't load plugin

    allow for better control of conditional plugin loading

    values of when$:

    • boolean
    • function
    • env var ref
    • option ref?
    • other?
    opened by rjrodger 0
Releases(v3.22.0)
  • v3.22.0(Sep 26, 2020)

  • v3.7.0(Jul 18, 2018)

    • role:seneca,cmd:ping responds with instance and process metrics.
    • Fixed memory leak in history: https://github.com/senecajs/seneca/issues/680
    • Utility modules available via Seneca.util: Eraro, Jsonic, Nid, Patrun
    • meta.custom is now preserved properly over entire action pathway including transpo
    Source code(tar.gz)
    Source code(zip)
  • v3.6.0(May 28, 2018)

  • v3.5.0(May 14, 2018)

  • v3.3.0(Feb 7, 2017)

    3.3.0 2017-02-07

    • Action callback can omit Error parameter (hapi style): http://senecajs.org/api/#method-add
    • Minor updates for consistency with new API docs: http://senecajs.org/api
    • Updated use-plugin to 0.3.2.
    • Plugin options are now consistent with global options after plugin load.
    Source code(tar.gz)
    Source code(zip)
  • v3.2.1(Sep 27, 2016)

  • v3.2.0(Sep 27, 2016)

    Summary

    This release corrects timeout regressions in the Gate Executor which ultimately led to memory leaks. Provisional support for .inward() and .outward() api methods has been added. These will be documented at a later date.

    CHANGELOG

    The Change Log below can be found in /CHANGES.md.

    • Added .inward() api method.
    • Added .outward() api method.
    • Made logging safely stringify input.
    • Fixed memory leak / timeout bug in gate-executor.

    Please visit http://senecajs.org/ for more information on support and how to contribute.

    Source code(tar.gz)
    Source code(zip)
  • v3.1.0(Sep 16, 2016)

    Summary

    This release corrects log filter regressions and issues where some types of match failed even though they should succeed. Additional minor improvements have been made too.

    CHANGELOG

    The Change Log below can be found in /CHANGES.md.

    • Correct issue with log handlers not working via command line
    • Extracted out log handling into seneca-log-filters for ease of reuse in custom loggers
    • Replaced the default logger filter logic with seneca-log-filters
    • Bumped patrun to correct incorrect matches with partial patterns due to missing catchall
    • Added error handling example in docs/examples/error-handling.js.
    • Changed boot log message from 'hello' to 'seneca-started'.
    • Updated salestax examples to work correctly.
    • Removed old legacy parsing handlers as they caused crashes
    • Added testable transport links

    Please visit http://senecajs.org/ for more information on support and how to contribute.

    Source code(tar.gz)
    Source code(zip)
  • v3.0.0(Aug 26, 2016)

    Summary

    This release focuses on making the core smaller and more stable. All default plugins, except for seneca-transport have been removed. The head-line feature for 3.0 is the ability to add logging adaptors to Seneca and defaulting to JSON output instead of pretty logging.

    CHANGELOG

    The Change Log below can be found in /CHANGES.md.

    • Refactored 'old' logging into it's own external plugin; seneca-legacy-logger.
    • Added new adaptor based JSON logging. External loggers can now be used with Seneca.
    • Created new 'built-in' logger which is used as the default logger if none are provided.
    • Corrected bug in Seneca.util.deepextend via Lodash version bump.
    • Updated gate-executor plugin to fix issues in load determinism and generally improve perf.
    • Replaced large swathes custom code with Lodash to improve speed and reliability.
    • Exposed parsepattern function via seneca.util.parsepattern as required by seneca-chain to function.
    • Removed 'dead' code marked legacy. Updated other parts of codebase with legacy notes for v.next.
    • Removed default settings for seneca-admin as it is not a default loaded plugin.
    • Set options.actcache.active to be false by default. Disables actcache feature by default.
    • Moved close_signals from options.internal to options.system.
    • Moved catchall from options.internal to options.system.
    • Removed options.schema as it was only partially checking and needs a rethink.
    • Removed mem-store as a required dependency in the package.
    • Devolved store logic in 'store.js' fully to seneca-entity. Entites are now 'fully removed'.
    • Devolved chain functionality into seneca-chain and removed from library. Moved all related tests.
    • Devolved pin functionality into seneca-pin and removed from library. Moved all related tests.
    • Removed seneca-web as a default loaded plugin. Removed related tests. Removed from package.
    • Removed seneca-cluster as a default loaded plugin. Removed related tests. Removed from package.
    • Removed seneca-seneca as a default loaded plugin. Removed related tests. Removed from package.
    • Removed seneca-echo as a default loaded plugin. Removed related tests. Removed from package.
    • Removed seneca-basic as a default loaded plugin. Removed related tests. Removed from package.
    • Removed seneca-repl as a default loaded plugin. Removed related tests. Removed from package.
    • Removed seneca-parambulator as a default loaded plugin. Removed related tests, etc.
    • Removed parambulator as a default loaded plugin. Removed related tests. Removed from package.
    • Removed joi as a default loaded plugin. Removed related tests. Removed from package.
    • Moved min required version of Node to greater than 4.0. 0.10 and 0.12 are no longer supported.
    • Added support for Node 6.x with minimal changes to account for api differences.
    • Removed LTS doc as it gives the wrong information. Website update to follow.
    • Updated all dependencies. Locked deps because of 0.x support have been updated too.
    • Modified tests to account for breaking changes in both lab and code after updating to latest.
    • Updated eslint-config-seneca with local rules and removed.
    • Corrected peer dependency issues around linting plugins.
    • Annotations are no longer stored in the repo and must be generated locally.
    • Annotations are now found in docs/annotated
    • Annotations now work for the whole library, not just seneca.js
    • Coverage report now generates as /docs/coverage.html and is not stored in the repo.
    • Coverage and Annotations can now be generated via npm run coverage & npm run annotate.
    • Paired back and updated travis file. Plugins are now tested via seneca-test-rig instead of with Seneca.
    • Moved old examples into folders & added 5 examples showing more concepts see docs/examples
    • Removed ALL redundant code files from test,stubs in test/stubs folder. All tests are now in the root.
    • Added test for exportmap in plugins to export values and functions; see /test/plugin.test.js:L23
    • Removed old release scripts in favour of docs/examples/create-a-release.md
    • Now using seneca-test-rig for plugin testing.

    Important

    Plugins in the /senecajs org are being updated to support 3.x. Modules that support this release will be marked as such in their README's.

    We are having issues modules listed below. If you are using any of these modules we recommend you not upgrade until the next point release of each module.

    • seneca-web
    • seneca-auth

    Node support is now as follows:

    • 4.x, 6.x

    Support has been dropped for,

    • 0.10, 0.12, 5.x

    Logging adaptor examples

    Documentation will come soon after release, for now we have a bunch of example adaptors to give you an idea how to use the feature for your own needs.

    • The new default log adaptor: here
    • A simple example log adaptor: here
    • Legacy log adaptor: here

    Plus,

    Upgrade Steps

    Adding back in removed modules

    The following packages have been removed as defaults,

    • seneca-web
    • seneca-cluster
    • seneca-echo
    • seneca-basic
    • seneca-parambulator

    In order to keep using these modules you will need to npm install them and require them into your services as seen below. Replace module-name with the name of the module(s) you wish to load

    const Seneca = require('seneca')
    
    const seneca = Seneca()
    seneca.use(require('module-name'))
    ...
    

    New plugins for old functionality

    New plugins have been created to support old, devolved, functionality,

    • Chaining functionality devolved to seneca-chain
    • Pin functionality devolved to seneca-pin
    • Pretty logging functionality devolved to seneca-legacy-logger

    In order to keep using these features you will need to npm install them and require them into your services as seen below. Replace devolved-module_name with the name of the module(s) you wish to load

    const Seneca = require('seneca')
    
    const seneca = Seneca()
    seneca.use(require('devolved-module-name'))
    ...
    

    Settings changes

    The following default settings have been changed or removed.

    • options.admin removed (seneca-admin related)
    • options.actcache.active to be false by default. Disables actcache feature by default.
    • options.internals.close_signals from options.internal to options.system.
    • options.internals.close_signals from options.internal to options.system.
    • options.schema removed.

    Special Thanks

    Please visit http://senecajs.org/ for more information on support and how to contribute.

    Source code(tar.gz)
    Source code(zip)
  • v2.0.0(Mar 22, 2016)

    Summary

    The major change is that the entity plugin is no longer installed and used by default.

    Upgrade Steps

    If you depend on seneca-entity you will need to add them back into your project. Please update your package.json to include the senecia-entity module. Afterwards, add a seneca.use statement to require it into your seneca instance. Below is an example of what this may look like.

    const Seneca = require('seneca');
    const seneca = Seneca();
    seneca.use(require('seneca-entity');
    
    ...
    

    Change Log

    Please view the change log for a list of changes through the years.

    Please visit http://senecajs.org/ for more information on support and how to contribute

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Mar 23, 2016)

    Summary

    After 5 years (original seneca commit) its time to mark Seneca as stable and release version 1.0.0. We will maintain the first major version in a long term support plan. This means that any critical bugs will be fixed and new versions published. You can also expect to see enhancements and minor release versions in the future.

    Change Log

    Please view the change log for a list of changes through the years.

    Credits

    Version 1.0.0 wouldn't be possible without the hard work from the many contributors who have helped the project through the years. Richard Rodger, in particular deserves special recognition, as seneca is his creation.

    Long Term Support Plan

    At the moment we are formalizing an LTS plan. That being said, this release is considered a LTS release. The details of what this means are found under the LTS document in the seneca repo.

    Please visit http://senecajs.org/ for more information on support and how to contribute

    Source code(tar.gz)
    Source code(zip)
Owner
Seneca Microservices Framework
for node.js
Seneca Microservices Framework
🔬 Writing reliable & fault-tolerant microservices in Node.js

A Node.js microservices toolkit for the NATS messaging system Run on repl.it Node: v6+ Documentation: https://hemerajs.github.io/hemera/ Lead Maintain

HemeraJs 800 Dec 14, 2022
Asynchronous HTTP microservices

Disclaimer: Micro was created for use within containers and is not intended for use in serverless environments. For those using Vercel, this means tha

Vercel 10.3k Jan 4, 2023
Zeronode - minimal building block for NodeJS microservices

Zeronode - minimal building block for NodeJS microservices Why Zeronode? Installation Basics Benchmark API Examples Basic Examples Basic Examples [Adv

Steadfast 120 Oct 21, 2022
Fast, unopinionated, minimalist web framework for node.

Fast, unopinionated, minimalist web framework for node. const express = require('express') const app = express() app.get('/', function (req, res) {

null 59.5k Jan 5, 2023
A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications on top of TypeScript & JavaScript (ES6, ES7, ES8) 🚀

A progressive Node.js framework for building efficient and scalable server-side applications. Description Nest is a framework for building efficient,

nestjs 53.2k Dec 31, 2022
Expressive middleware for node.js using ES2017 async functions

Expressive HTTP middleware framework for node.js to make web applications and APIs more enjoyable to write. Koa's middleware stack flows in a stack-li

Koa.js 33.5k Jan 4, 2023
Realtime MVC Framework for Node.js

Website Get Started Docs News Submit Issue Sails.js is a web framework that makes it easy to build custom, enterprise-grade Node.js apps. It is design

Balderdash 22.4k Dec 31, 2022
🥚 Born to build better enterprise frameworks and apps with Node.js & Koa

Features Built-in Process Management Plugin System Framework Customization Lots of plugins Quickstart Follow the commands listed below. $ mkdir showca

egg 18.3k Dec 29, 2022
Fast and low overhead web framework, for Node.js

An efficient server implies a lower cost of the infrastructure, a better responsiveness under load and happy users. How can you efficiently handle the

Fastify 26k Jan 2, 2023
📦🔐A lightweight private proxy registry build in Node.js

Version 6 (Development branch) Looking for Verdaccio 5? Check branch 5.x. Verdaccio is a simple, zero-config-required local private npm registry. No n

Verdaccio 14.3k Dec 31, 2022
The future of Node.js REST development

restify is a framework, utilizing connect style middleware for building REST APIs. For full details, see http://restify.com Follow restify on Usage Se

restify 10.6k Jan 2, 2023
🚀 The Node.js Framework highly focused on developer ergonomics, stability and confidence

Sponsored by FOSS United is a non-profit foundation that aims at promoting and strengthening the Free and Open Source Software (FOSS) ecosystem in Ind

AdonisJS Framework 13.4k Dec 31, 2022
Use full ES2015+ features to develop Node.js applications, Support TypeScript.

ThinkJS Use full ES2015+ features to develop Node.js applications, Support TypeScript. 简体中文文档 Installation npm install -g think-cli Create Application

ThinkJS 5.3k Dec 30, 2022
MVC framework making it easy to write realtime, collaborative applications that run in both Node.js and browsers

Derby The Derby MVC framework makes it easy to write realtime, collaborative applications that run in both Node.js and browsers. Derby includes a powe

DerbyJS 4.7k Dec 23, 2022
Node.js framework

Node.js framework Total.js framework is a framework for Node.js platfrom written in pure JavaScript similar to PHP's Laravel or Python's Django or ASP

Total.js 4.2k Jan 2, 2023
API Services Made Easy With Node.js

Nodal API Services Made Easy with Node.js View the website at nodaljs.com. Nodal is a web server and opinionated framework for building data manipulat

Keith Horwood 4.5k Dec 26, 2022
🍔 A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 🌈

Midway - 一个面向未来的云端一体 Node.js 框架 English | 简体中文 ?? 欢迎观看 Midway Serverless 2.0 发布会回放: https://www.bilibili.com/video/BV17A411T7Md 《Midway Serverless 发布

Midway.js 6.3k Jan 8, 2023
:evergreen_tree: Modern Web Application Framework for Node.js.

Trails is a modern, community-driven web application framework for Node.js. It builds on the pedigree of Rails and Grails to accelerate development by

Trails 1.7k Dec 19, 2022
Marble.js - functional reactive Node.js framework for building server-side applications, based on TypeScript and RxJS.

Functional reactive Node.js framework for building server-side applications, based on TypeScript and RxJS. Ecosystem Name Description @marblejs/core F

Marble.js 2.1k Dec 16, 2022