diff --git a/LICENSE.txt b/LICENSE.txt
index ef1b55c..a159cd4 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,6 +1,6 @@
The MIT License
-Copyright (c) 2013 Richard Rodger
+Copyright (c) 2013 - 2016 Richard Rodger
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 689039c..0f1bdf6 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
+
+> [Seneca.js](https://github.com/senecajs/)
+
+
# seneca-examples - Node.js plugin examples for the Seneca toolkit
This repository is a collection of simple examples to get you started
@@ -13,9 +17,20 @@ example for a fully commented walk through of the example.
* [simple-plugin](//github.com/rjrodger/seneca-examples/tree/master/simple-plugin): Create a simple Seneca plugin, including unit tests.
* [api-server](//github.com/rjrodger/seneca-examples/tree/master/api-server): building a REST server with Seneca
* [plugin-web](//github.com/rjrodger/seneca-examples/tree/master/plugin-web): creating plugins that expose web user interfaces
- * [micro-services](github.com/rjrodger/seneca-examples/tree/master/micro-services): create a small micro-services system
+ * [micro-services](//github.com/rjrodger/seneca-examples/tree/master/micro-services): create a small micro-services system
* [user-accounts](//github.com/rjrodger/seneca-examples/tree/master/user-accounts): A user account system, showing login/logout logic.
* [shopping-cart](//github.com/rjrodger/seneca-examples/tree/master/shopping-cart): A shopping cart example, showing how plugins expose additional HTTP APIs.
+## Contributing
+
+The [Senecajs org](https://github.com/senecajs/) encourage open and safe participation.
+If you feel you can help in any way, be it with documentation, examples,
+extra testing, or new features please get in touch. - Before contributing please review [here](http://senecajs.org/contribute/code-of-conduct.html)
+
+
+## License
+Copyright Richard Rodger and other contributors 2013 - 2016, Licensed under [MIT](./LICENSE.txt).
+
+
diff --git a/api-server/.eslintrc b/api-server/.eslintrc
new file mode 100644
index 0000000..b26e0fd
--- /dev/null
+++ b/api-server/.eslintrc
@@ -0,0 +1,4 @@
+{
+ "extends": ["seneca"]
+}
+
diff --git a/api-server/README.md b/api-server/README.md
index a15a283..bcfd464 100644
--- a/api-server/README.md
+++ b/api-server/README.md
@@ -1,6 +1,28 @@
+## Setup:
+```
+npm install
+```
+
+## Run:
+the server with:
+```
+npm run start
+```
+
+the client, in a separate terminal, with:
+```
+npm run client
+```
-Notes:
+Try running the client more than once. Some operations only work the
+first time! For example, you can't create a new entity with the same
+id as an existing one. Nor can you access a deleted entity.
+
+You can get a view of the current state of the data by opening:
+http://localhost:3000/mem-store/dump
+
+## Notes:
This example provides a simple structure for an API server. The server
exposes a product catalog API. The API provides a REST interface, and
@@ -18,7 +40,7 @@ some custom endpoints:
This is a basic API, and does not handle permissions. However it does
require a (hardcoded) token to be accessed. This is enforced using the
-_startware_ feature of [seneca-web](github.com/rjrodger/seneca-web)
+_startware_ feature of [seneca-web](https://github.com/senecajs/seneca-web).
The API is defined by the _api.js_ plugin. This defines a set of
action patterns that exist merely to translate HTTP requests into
@@ -28,7 +50,7 @@ The translation is done manually for the _/hello_ and
_/product/:id/star_ endpoints, using _seneca-web's_ mapping facility.
The HTTP REST API for product data is provided by the
-[seneca-jsonrest-api](github.com/rjrodger/seneca-jsonrest-api) plugin.
+[seneca-jsonrest-api](https://github.com/rjrodger/seneca-jsonrest-api) plugin.
The business logic is provided by the plugin
_product_catalog.js_. This is a seneca plugin that exposes a single
@@ -41,19 +63,5 @@ _product_catalog.js_ in it's own process, and also the data access
patterns _role:entity,..._.
-Setup:
-$ npm install
-
-Run the server with:
-$ node app.js --seneca.log.all
-Run the client, in a separate terminal, with:
-$ node client.js
-
-Try running the client more than once. Some operations only work the
-first time! For example, you can't create a new entity with the same
-id as an existing one. Nor can you access a deleted entity.
-
-You can get a view of the current state of the data by opening:
-http://localhost:3000/mem-store/dump
diff --git a/api-server/api.js b/api-server/api.js
index 53e9d8e..7118662 100644
--- a/api-server/api.js
+++ b/api-server/api.js
@@ -1,49 +1,41 @@
// PUBLIC DOMAIN
-"use strict";
+'use strict'
-module.exports = function api( options ) {
+module.exports = function api (options) {
var seneca = this
-
seneca.add('role:api,info:hello', hello)
-
seneca.add('role:api,product:star', get_star)
seneca.add('role:api,product:handle_star', handle_star)
-
-
- seneca.add('init:api',function(args,done){
-
+ seneca.add('init:api', function (args, done) {
// Order is significant here!
-
- seneca.act('role:web',{use:{
- prefix:'/',
- pin:'role:api,info:*',
- map:{
- hello:true
+ seneca.act('role:web', {use: {
+ prefix: '/',
+ pin: 'role:api,info:*',
+ map: {
+ hello: true
}
}})
-
seneca.use(
- {name:'jsonrest-api',tag:'product'},
+ {name: 'jsonrest-api', tag: 'product'},
{
prefix: '/',
- list: {embed:'list'},
- pin: { name:'product' },
+ list: {embed: 'list'},
+ pin: { name: 'product' },
startware: verify_token,
allow_id: true
})
-
- seneca.act('role:web',{use:{
- prefix:'/product',
- pin:'role:api,product:*',
+ seneca.act('role:web', {use: {
+ prefix: '/product',
+ pin: 'role:api,product:*',
startware: verify_token,
- map:{
- star: {
- alias:'/:id/star'
+ map: {
+ star: {
+ alias: '/:id/star'
},
- handle_star:{
- PUT:true,
- DELETE:true,
- alias:'/:id/star'
+ handle_star: {
+ PUT: true,
+ DELETE: true,
+ alias: '/:id/star'
}
}
}})
@@ -51,66 +43,57 @@ module.exports = function api( options ) {
done()
})
-
var internal_err = {
- http$: {status:500},
- why: 'Internal error.'
+ http$: {status: 500},
+ why: 'Internal error.'
}
var bad_input = {
- http$: {status:400},
- why: 'Bad input.'
+ http$: {status: 400},
+ why: 'Bad input.'
}
-
- function verify_token(req,res,next) {
+ function verify_token (req, res, next) {
var token = req.headers['api-access-token']
-
- // Hard coded token for this example!!!
- if( '1234' == token ) return next();
-
- res.writeHead(401,"Access denied.")
+ // Hard coded token for this example!!!
+ if('1234' === token) return next()
+ res.writeHead(401, 'Access denied.')
res.end()
}
-
- function hello( args, done ) {
- done(null,{msg:'hello!'})
+ function hello (args, done) {
+ done(null, {msg: 'hello!'})
}
- function get_star( args, done ) {
- this.make$('product').load$(args.id,function(err,res){
- if(err) return done(null,internal_err);
- if(!res) return done(null,bad_input);
-
- return done(null,{
+ function get_star (args, done) {
+ this.make$('product').load$(args.id, function (err, res) {
+ if(err) return done(null, internal_err)
+ if(!res) return done(null, bad_input)
+ return done(null, {
product: res.id,
- star: res.star
+ star: res.star
})
})
}
- function handle_star( args, done ) {
+ function handle_star (args, done) {
this.act(
- 'role:product,cmd:star',
+ 'role:product,cmd:star',
{
// product id
- id:args.id,
-
+ id: args.id,
// PUT means star, DELETE means unstar
- star:('PUT'===args.req$.method)
+ star: ('PUT' === args.req$.method)
},
- function(err,res){
- if(err) return done(null,internal_err);
- if(!res.ok) return done(null,bad_input)
-
- return done(null,{
- product: res.id,
- star: res.star
- })
- }
- )
+ function (err, res) {
+ if(err) return done(null, internal_err)
+ if(!res.ok) return done(null, bad_input)
+ return done(null, {
+ product: res.id,
+ star: res.star
+ })
+ }
+ )
}
-
}
diff --git a/api-server/app.js b/api-server/app.js
index 8df455a..5e2b31a 100644
--- a/api-server/app.js
+++ b/api-server/app.js
@@ -1,16 +1,14 @@
// PUBLIC DOMAIN
-
var seneca = require('seneca')()
.use('./product_catalog')
.use('./api')
- .ready(function(){
+ .ready(function () {
this.make$('product')
- .make$({id$:0,name:'Apple',price:99,star:0}).save$()
- .make$({id$:1,name:'Orange',price:199,star:0}).save$()
+ .make$({id$: 0, name: 'Apple', price: 99, star: 0}).save$()
+ .make$({id$: 1, name: 'Orange', price: 199, star: 0}).save$()
})
-var app = require('express')()
- .use( require('body-parser').json() )
- .use( seneca.export('web') )
+require('express')()
+ .use(require('body-parser').json())
+ .use(seneca.export('web'))
.listen(3000)
-
diff --git a/api-server/client.js b/api-server/client.js
index 1622671..5067884 100644
--- a/api-server/client.js
+++ b/api-server/client.js
@@ -1,51 +1,39 @@
-var util = require('util')
+var util = require ('util')
-var request = require('request')
-var _ = require('lodash')
+var Request = require('request')
+var _ = require('lodash')
var base = 'http://localhost:3000/'
-var headers = {'api-access-token':'1234'}
-
-
-;print('get',{url:base+'hello',headers:headers},function(){
-
-;print('get',{url:base+'product',headers:headers},function(){
-;print('get',{url:base+'product/0',headers:headers},function(){
-;print('get',{url:base+'product/1',headers:headers},function(){
-;print('get',{url:base+'product/2',headers:headers},function(){
-
-;print('post',{url:base+'product',headers:headers,json:{
- id$:2, name:'Pear', price:299
-}},function(){
-
-;print('get',{url:base+'product/2',headers:headers},function(){
-
-;print('put',{url:base+'product/2',headers:headers,json:{
- name:'Pear', price:Math.floor(300*Math.random())
-}},function(){
-
-;print('get',{url:base+'product/2',headers:headers},function(){
-
-;print('del',{url:base+'product/1',headers:headers},function(){
-;print('get',{url:base+'product/1',headers:headers},function(){
-
-;print('get',{url:base+'product/0/star',headers:headers},function(){
-;print('put',{url:base+'product/0/star',headers:headers},function(){
-;print('get',{url:base+'product/0/star',headers:headers},function(){
-
-})})})})})})})})})})})})})})
-
-
-
-// utility function to pretty print request results
-function print() {
+var headers = {'api-access-token': '1234'}
+
+
+;print('get', {url: base + 'hello', headers: headers}, function () {
+ ;print('get', {url: base + 'product', headers: headers}, function () {
+ ;print('get', {url: base + 'product/0', headers: headers}, function () {
+ ;print('get', {url: base + 'product/1', headers: headers}, function () {
+ ;print('get', {url: base + 'product/2', headers: headers}, function () {
+ ;print('post', {url: base + 'product', headers: headers, json: {
+ id$: 2, name: 'Pear', price: 299
+ }}, function () {
+ ;print('get', {url: base + 'product/2', headers: headers}, function () {
+ ;print('put', {url: base + 'product/2', headers: headers, json: {
+ name: 'Pear', price: Math.floor(300 * Math.random())
+ }}, function () {
+ ;print('get', {url: base + 'product/2', headers: headers}, function () {
+ ;print('del', {url: base + 'product/1', headers: headers}, function () {
+ ;print('get', {url: base + 'product/1', headers: headers}, function () {
+ ;print('get', {url: base + 'product/0/star', headers: headers}, function () {
+ ;print('put', {url: base + 'product/0/star', headers: headers}, function () {
+ ;print('get', {url: base + 'product/0/star', headers: headers}, function () {
+ }) }) }) }) }) }) }) }) }) }) }) }) }) })
+
+ // utility function to pretty print request results
+function print () {
var a = Array.prototype.slice.call(arguments)
var mstr = a[0]
-
- var n = _.isFunction( a[a.length-1] ) ? a.pop() : null
-
- request[mstr].apply(request, a.slice(1).concat(function(err,res,body){
- console.log(mstr,res.req.path,res.statusCode,err||body)
+ var n = _.isFunction(a[ a.length - 1 ]) ? a.pop() : null
+ Request[mstr].apply(Request, a.slice(1).concat(function (err, res, body) {
+ console.log(mstr, res.req.path, res.statusCode, err || body)
!err && n && n()
}))
}
diff --git a/api-server/package.json b/api-server/package.json
index 73cba08..9a46937 100644
--- a/api-server/package.json
+++ b/api-server/package.json
@@ -7,12 +7,22 @@
"repository": "",
"author": "Richard Rodger",
"license": "MIT",
+ "scripts": {
+ "start": "node app.js --seneca.log.all",
+ "client": "node client.js"
+ },
"dependencies": {
- "body-parser": "~1.11.0",
- "express": "~4.11.1",
- "lodash": "~3.0.1",
- "request": "~2.51.0",
+ "body-parser": "~1.15.1",
+ "express": "~4.13.4",
+ "lodash": "~4.13.1",
+ "request": "~2.72.0",
"seneca": "plugin",
+ "seneca-entity": "0.1.1",
"seneca-jsonrest-api": "~0.3.1"
+ },
+ "devDependencies": {
+ "eslint-config-seneca": "2.x.x",
+ "eslint-plugin-standard": "1.x.x",
+ "eslint-plugin-hapi": "4.x.x"
}
}
diff --git a/api-server/product_catalog.js b/api-server/product_catalog.js
index 07a922a..63b0c0c 100644
--- a/api-server/product_catalog.js
+++ b/api-server/product_catalog.js
@@ -1,37 +1,31 @@
// PUBLIC DOMAIN
-"use strict";
+'use strict'
-module.exports = function product_catalog( options ) {
+module.exports = function product_catalog (options) {
var seneca = this
-
seneca.add('role:product,cmd:star', cmd_star)
-
-
- function cmd_star( args, done ) {
+ function cmd_star (args, done) {
var seneca = this
-
seneca
.make$('product')
- .load$(args.id,function( err, product ) {
- if(err) return done(err);
-
- if( product ) {
- product.star = Math.max(0,(
- (product.star||0) +
- ((args.star||true) ? +1 : -1 )))
-
- product.save$(function(err,product){
- if(err) return done(err);
-
- return done(null,{
- ok: true,
- id: product.id,
+ .load$(args.id, function (err, product) {
+ if(err) return done(err)
+ if(product) {
+ product.star = Math.max(0, (
+ (product.star || 0) +
+ ((args.star && true) ? +1 : -1)))
+
+ product.save$(function (err, product) {
+ if(err) return done(err)
+
+ return done(null, {
+ ok: true,
+ id: product.id,
star: product.star
})
})
}
- else return done(null,{ok:false})
+ else return done(null, {ok: false})
})
}
-
}
diff --git a/api-server/seneca.options.js b/api-server/seneca.options.js
index 2bcdf80..9667d31 100644
--- a/api-server/seneca.options.js
+++ b/api-server/seneca.options.js
@@ -1,4 +1,4 @@
module.exports = {
- 'mem-store': { web: { dump:true } },
- web: {debug: { service:true } },
+ 'mem-store': {web: {dump: true}},
+ 'web': {debug: {service: true}}
}
diff --git a/data-entities/.eslintrc b/data-entities/.eslintrc
new file mode 100644
index 0000000..b26e0fd
--- /dev/null
+++ b/data-entities/.eslintrc
@@ -0,0 +1,4 @@
+{
+ "extends": ["seneca"]
+}
+
diff --git a/data-entities/README.md b/data-entities/README.md
index 9171e1f..01b1b74 100644
--- a/data-entities/README.md
+++ b/data-entities/README.md
@@ -1,9 +1,29 @@
-For an introduction to Seneca data entities, please read the
-[senecajs.org tutorial](http://senecajs.org/data-entities.html).
+## Setup:
+```
+npm install
+```
+
+* Note: seneca-level-store compiles the level modules, as they are
+native. If this does not work on your platform (e.g. Windows), just
+comment out the level-store code.
+
+
+## Run:
+```
+npm run build
+```
+```
+npm run start
+```
-Notes:
+For detailed logging, try:
+```
+npm run details
+```
+
+## Notes:
The code in main.js shows you how to save data entities to different
places. The two jsonfile-store and single level-store data store
@@ -22,18 +42,11 @@ on disk. The data is also loaded independently of Seneca to verify
that it actually has been persisted! The entity.native$ method is used
to do this, as it exposes the underlying database API.
+For an introduction to Seneca data entities, please read the
+[senecajs.org tutorial](http://senecajs.org/tutorials/understanding-data-entities.html).
-Setup:
-$ npm install
-Note: seneca-level-store compiles the level modules, as they are
-native. If this does not work on your platform (e.g. Windows), just
-comment out the level-store code.
-Run with:
-$ node main.js
-For detailed logging, try:
-$ node main.js --seneca.log.all
diff --git a/data-entities/main.js b/data-entities/main.js
index d92e508..7993933 100644
--- a/data-entities/main.js
+++ b/data-entities/main.js
@@ -1,68 +1,68 @@
-/* Copyright (c) 2013-2015 Richard Rodger, MIT License */
-"use strict";
-
-var fs = require('fs')
-var util = require('util')
+/* Copyright (c) 2013-2016 Richard Rodger, MIT License */
+'use strict'
+var Fs = require('fs')
+var Util = require('util')
var seneca = require('seneca')()
-// Use two separate instances of jsonfile-store, each looking after a
-// different set of data entities
-seneca.use( 'jsonfile-store$foo', { folder:'foo-data', map:{'-/foo/-':'*'}})
-seneca.use( 'jsonfile-store$bar', { folder:'bar-data', map:{'-/bar/-':'*'}})
-
+/* Use two separate instances of jsonfile-store, each looking after a
+ different set of data entities */
+seneca.use('jsonfile-store$foo', {folder: 'foo-data', map: {'-/foo/-': '*'}})
+seneca.use('jsonfile-store$bar', {folder: 'bar-data', map: {'-/bar/-': '*'}})
+if (seneca.version >= '2.0.0') {
+ seneca.use('entity')
+}
// Use a different data store for another set of data entities
-seneca.use( 'level-store', { folder:'zed-data', map:{'-/zed/-':'*'}})
+seneca.use('level-store', {folder: 'zed-data', map: {'-/zed/-': '*'}})
// Everything else goes into the default mem-store
seneca
- .make$('foo/red',{a:1})
- .save$(function(err,foo_red){
- if(err) return console.error('foo_red',err);
- var fc = fs.readFileSync(__dirname+'/foo-data/foo_red/'+foo_red.id+'.json')
- console.log('entity:'+foo_red+', file contents:'+fc)
- do_bar_green(this)
- })
+.make$('foo/red', {a: 1})
+.save$(function (err, foo_red) {
+ if(err) return console.error('foo_red', err)
+ var fc = Fs.readFileSync(__dirname + '/foo-data/foo_red/' + foo_red.id + '.json')
+ console.log('entity:' + foo_red + ', file contents:' + fc)
+ do_bar_green(this)
+})
-function do_bar_green(seneca) {
+function do_bar_green (seneca) {
seneca
- .make$('bar/green',{b:2})
- .save$(function(err,bar_green){
- if(err) return console.error('bar_green',err);
- var fc = fs.readFileSync(__dirname+'/bar-data/bar_green/'+
- bar_green.id+'.json')
- console.log('entity:'+bar_green+', file contents:'+fc)
- do_zed_blue(seneca)
- })
+ .make$('bar/green', {b: 2})
+ .save$(function (err, bar_green) {
+ if(err) return console.error('bar_green', err)
+ var fc = Fs.readFileSync(__dirname + '/bar-data/bar_green/' +
+ bar_green.id + '.json')
+ console.log('entity:' + bar_green + ', file contents:' + fc)
+ do_zed_blue(seneca)
+ })
}
-function do_zed_blue(seneca) {
+function do_zed_blue (seneca) {
seneca
- .make$('zed/blue',{c:3})
- .save$(function(err,zed_blue){
- if(err) return console.error('zed_blue',err);
- zed_blue.native$(function(err,level){
- if(err) return console.error('zed_blue.native$',err);
- level.get(zed_blue.id,function(err,data){
- console.log('entity:'+zed_blue+' level data:'+util.inspect(data))
- do_qaz_yellow(seneca)
- })
+ .make$('zed/blue', {c: 3})
+ .save$(function (err, zed_blue) {
+ if(err) return console.error('zed_blue', err)
+ zed_blue.native$(function (err, level) {
+ if(err) return console.error('zed_blue.native$', err)
+ level.get(zed_blue.id, function (err, data) {
+ if(err) return console.error('zed_blue.id', err)
+ console.log('entity:' + zed_blue + ' level data:' + Util.inspect(data))
+ do_qaz_yellow(seneca)
})
})
+ })
}
-function do_qaz_yellow(seneca) {
+function do_qaz_yellow (seneca) {
seneca
- .make$('qaz/yellow',{d:4})
- .save$(function(err,qaz_yellow){
- if(err) return console.error('qaz_yellow',err);
- qaz_yellow.native$(function(err,entmap){
- if(err) return console.error('qaz_yellow.native$',err);
- var dc = entmap.qaz.yellow[qaz_yellow.id]
- console.log('entity:'+qaz_yellow+
- ', data contents:'+util.inspect(dc))
- })
- })
+ .make$('qaz/yellow', {d: 4})
+ .save$(function (err, qaz_yellow) {
+ if(err) return console.error('qaz_yellow', err)
+ qaz_yellow.native$(function (err, entmap) {
+ if(err) return console.error('qaz_yellow.native$', err)
+ var dc = entmap.qaz.yellow[qaz_yellow.id]
+ console.log('entity:' + qaz_yellow + ', data contents:' + Util.inspect(dc))
+ })
+ })
}
-
diff --git a/data-entities/package.json b/data-entities/package.json
index 21c3c94..68cbd69 100644
--- a/data-entities/package.json
+++ b/data-entities/package.json
@@ -7,9 +7,20 @@
"repository": "",
"author": "Richard Rodger",
"license": "MIT",
+ "scripts": {
+ "start": "node main.js ",
+ "details": "node main.js --seneca.log.all",
+ "build": "mkdir bar-data foo-data zed-data"
+ },
"dependencies": {
- "seneca": "plugin",
- "seneca-level-store": "~0.2.1",
- "seneca-jsonfile-store": "~0.2.2"
+ "seneca": "2.1.0",
+ "seneca-entity": "0.1.1",
+ "seneca-jsonfile-store": "~0.2.2",
+ "seneca-level-store": "~0.2.1"
+ },
+ "devDependencies": {
+ "eslint-config-seneca": "2.x.x",
+ "eslint-plugin-standard": "1.x.x",
+ "eslint-plugin-hapi": "4.x.x"
}
}
diff --git a/micro-services/.eslintrc b/micro-services/.eslintrc
new file mode 100644
index 0000000..b26e0fd
--- /dev/null
+++ b/micro-services/.eslintrc
@@ -0,0 +1,4 @@
+{
+ "extends": ["seneca"]
+}
+
diff --git a/micro-services/README.txt b/micro-services/README.md
similarity index 75%
rename from micro-services/README.txt
rename to micro-services/README.md
index a86017a..43fddef 100644
--- a/micro-services/README.txt
+++ b/micro-services/README.md
@@ -1,4 +1,10 @@
+## Setup:
+```
+npm install
+```
+
+## Run:
Runs the following services:
* offer-service
@@ -6,9 +12,15 @@ Runs the following services:
* web-app
You can run these individually in separate terminals with:
-
-$ node services/offer-service.js
-... etc
+```
+node services/offer-service.js
+```
+```
+node services/user-details.js
+```
+```
+node services/web-app.js
+```
Optionally use --seneca.log.all to see the debug logs,
or --seneca.log=type:act just to see the actions
@@ -17,10 +29,10 @@ In the debug logs, the first field is the local system time, and the
second field is a unique identifer for the seneca instance. Use this
to observe how messages flow in the system.
-
For convenience, you can also run everything with:
-
-$ node index.js
+```
+npm run start
+```
This always prints merged debug logs for all services. The individual
logs are saved to the log folder.
@@ -34,8 +46,15 @@ The implementations of the seneca plugins used by the services are in
lib/*.js. Notice that the user-details service is just pulling out the
standard seneca-user plugin implementation into a separate service.
-Open http://localhost:3000 to see the services in action.
-Login with username:u1, password:u2
+To see the services in action open:
+```
+http://localhost:3000
+```
+
+* Login with:
+```
+username:user, password:user
+```
The offered product depends on your login status.
@@ -44,8 +63,8 @@ The user-details delivers user login and logout.
The offer-service delivers product offers based on the visitor
being identified (i.e. logged in) or not.
-This example is a vastly simplified version of Fred George's talk:
-http://oredev.org/2013/wed-fri-conference/implementing-micro-service-architectures
+This example is a vastly simplified version of Fred George's talk [implementing-micro-service-architectures]
+(http://oredev.org/oredev2013/2013/wed-fri-conference/implementing-micro-service-architectures.html)
diff --git a/micro-services/index.js b/micro-services/index.js
index c3698bd..9223725 100644
--- a/micro-services/index.js
+++ b/micro-services/index.js
@@ -2,11 +2,11 @@ var fs = require('fs')
var spawn = require('child_process').spawn
-var services = ['web-app','user-details','offer-service']
+var services = ['web-app', 'user-details', 'offer-service']
-services.forEach(function(service){
- var log = fs.createWriteStream('./log/'+service+'.log')
- var proc = spawn('node', ['./services/'+service+'.js','--seneca.log.all'])
+services.forEach(function (service) {
+ var log = fs.createWriteStream('./log/' + service + '.log')
+ var proc = spawn('node', ['./services/' + service + '.js', ' --seneca.log.all'])
proc.stdout.pipe(log)
proc.stderr.pipe(log)
@@ -14,6 +14,3 @@ services.forEach(function(service){
proc.stdout.pipe(process.stdout)
proc.stderr.pipe(process.stderr)
})
-
-
-
diff --git a/micro-services/lib/api.js b/micro-services/lib/api.js
index bcd51f4..dbd3649 100644
--- a/micro-services/lib/api.js
+++ b/micro-services/lib/api.js
@@ -3,25 +3,21 @@ module.exports = function( options ) {
var seneca = this
var plugin = 'api'
+ seneca.add({role: plugin, end: 'offer'}, end_offer)
- seneca.add( {role:plugin, end:'offer'}, end_offer)
-
-
- function end_offer( args, done ) {
+ function end_offer (args, done) {
var user = args.req$.seneca.user || {}
- this.act('role:offer,cmd:provide',{nick:user.nick},done)
+ this.act('role:offer,cmd:provide', {nick: user.nick}, done)
}
-
-
- seneca.act({role:'web', use:{
- prefix:'/api/',
- pin:{role:plugin,end:'*'},
- map:{
- 'offer': { GET:true },
+ seneca.act({role: 'web', use: {
+ prefix: '/api/',
+ pin: {role: plugin, end: '*'},
+ map: {
+ 'offer': { GET: true }
}
}})
- return {name:plugin};
+ return {name: plugin}
}
diff --git a/micro-services/lib/offer.js b/micro-services/lib/offer.js
index e19aac6..1733a30 100644
--- a/micro-services/lib/offer.js
+++ b/micro-services/lib/offer.js
@@ -3,16 +3,11 @@ module.exports = function( options ) {
var seneca = this
var plugin = 'offer'
+ seneca.add({role: plugin, cmd: 'provide'}, cmd_provide)
- seneca.add( {role:plugin, cmd:'provide'}, cmd_provide)
-
-
- function cmd_provide( args, done ) {
- if( args.nick ) return done(null,{product:'Apple'});
-
- return done(null,{product:'Orange'});
+ function cmd_provide (args, done) {
+ if (args.nick) return done(null, {product: 'Apple'})
+ return done(null, {product: 'Orange'})
}
-
-
- return {name:plugin};
+ return {name: plugin}
}
diff --git a/micro-services/package.json b/micro-services/package.json
index f960049..e89064a 100644
--- a/micro-services/package.json
+++ b/micro-services/package.json
@@ -3,16 +3,23 @@
"version": "0.1.0",
"description": "Seneca micro-services example",
"main": "index.js",
+ "author": "Richard Rodger",
+ "license": "MIT",
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "node index.js"
},
- "author": "",
- "license": "MIT",
"dependencies": {
- "body-parser": "~1.11.0",
- "express": "~4.11.2",
+ "body-parser": "~1.15.1",
+ "express": "~4.13.4",
"seneca": "plugin",
- "seneca-auth": "~0.4.0",
- "seneca-user": "~0.2.10"
+ "seneca-entity": "0.1.1",
+ "seneca-auth": "~1.0.1",
+ "seneca-user": "~1.0.2"
+ },
+ "devDependencies": {
+ "eslint-config-seneca": "2.x.x",
+ "eslint-plugin-standard": "1.x.x",
+ "eslint-plugin-hapi": "4.x.x"
}
}
diff --git a/micro-services/public/index.html b/micro-services/public/index.html
index cb22661..cdaf956 100644
--- a/micro-services/public/index.html
+++ b/micro-services/public/index.html
@@ -1,55 +1,34 @@
-
-
+
+
-
-
-
-Micro-Services
-
-
-Hi There!
-Have an !
-
-
-
-
-
-
-
-
-
Account
-
-Username:
-Name:
-
-
-
-
-
-
-
+
+ Micro-Services
+ Hi There!
+ Have an !
+
+
+
Account
+ Username:
+ Name:
+
+
diff --git a/micro-services/public/index.js b/micro-services/public/index.js
index 7bec0f9..4790ba5 100644
--- a/micro-services/public/index.js
+++ b/micro-services/public/index.js
@@ -1,31 +1,31 @@
$(function(){
- $('#login').submit(function(){
+ $('#login').submit(function() {
var data = {
username: $('#username').val(),
password: $('#password').val()
}
$.ajax({
- type: 'POST',
- url: '/auth/login',
- data: JSON.stringify(data),
- dataType: 'json',
+ type: 'POST',
+ url: '/auth/login',
+ data: JSON.stringify(data),
+ dataType: 'json',
contentType: 'application/json',
- success: showAccount
+ success: showAccount
})
-
+ console.log('DATA:', data)
return false
})
$('#logout').click(function(){
$.ajax({
- type: 'POST',
- url: '/auth/logout',
- data: '{}',
- dataType: 'json',
+ type: 'POST',
+ url: '/auth/logout',
+ data: '{}',
+ dataType: 'json',
contentType: 'application/json',
- success: showLogin
+ success: showLogin
})
})
@@ -34,21 +34,19 @@ $(function(){
$.ajax({type:'GET',url:'/api/offer',success:showOffer})
})
-
-function showAccount(instance) {
- if( instance.user ) {
+function showAccount (instance) {
+ if(instance.user) {
$('#user_nick').text(instance.user.nick)
$('#user_name').text(instance.user.name)
$('#content_login').slideUp()
$('#content_account').slideDown()
-
$.ajax({type:'GET',url:'/api/offer',success:showOffer})
}
}
-function showLogin(instance) {
- if( instance.user ) return showAccount(instance)
+function showLogin (instance) {
+ if(instance.user) return showAccount(instance)
$('#content_login').slideDown()
$('#content_account').slideUp()
@@ -57,6 +55,6 @@ function showLogin(instance) {
}
-function showOffer(offer) {
+function showOffer (offer) {
$('#offer').text(offer.product)
}
diff --git a/micro-services/services/offer-service.js b/micro-services/services/offer-service.js
index 697e6cb..cd88b1f 100644
--- a/micro-services/services/offer-service.js
+++ b/micro-services/services/offer-service.js
@@ -1,9 +1,6 @@
-require('seneca')()
+require('seneca') ()
.use('../lib/offer')
.listen(10202)
- .ready(function(){
- this.act({role:'offer',cmd:'provide'},console.log)
+ .ready(function () {
+ this.act({role: 'offer', cmd: 'provide'}, console.log)
})
-
-
-
diff --git a/micro-services/services/user-details.js b/micro-services/services/user-details.js
index 2751f23..baf81fa 100644
--- a/micro-services/services/user-details.js
+++ b/micro-services/services/user-details.js
@@ -2,8 +2,6 @@
require('seneca')()
.use('user')
.listen(10201)
- .ready(function(){
- this.act({role:'user',cmd:'register',nick:'u1',name:'U1',password:'u1'})
+ .ready(function () {
+ this.act({role: 'user', cmd: 'register', nick: 'user', name: 'user', password: 'user'})
})
-
-
diff --git a/micro-services/services/web-app.js b/micro-services/services/web-app.js
index 2002d88..22f8e3c 100644
--- a/micro-services/services/web-app.js
+++ b/micro-services/services/web-app.js
@@ -1,21 +1,18 @@
-var express = require('express')
-var bodyParser = require('body-parser')
-var seneca = require('seneca')()
-
+var Express = require('express')
+var BodyParser = require('body-parser')
+var seneca = require('seneca')()
seneca
.use('user')
.use('auth')
.use('../lib/api.js')
- .client({port:10202,pin:{role:'offer',cmd:'*'}})
- .client({port:10201,pin:{role:'user',cmd:'*'}})
-
-var app = express()
+ .client({port: 10202, pin: {role: 'offer', cmd: '*'}})
+ .client({port: 10201, pin: {role: 'user', cmd: '*'}})
-app.use( bodyParser.json() )
-app.use( seneca.export('web') )
-app.use( express.static('./public') )
+var app = Express()
+app.use(BodyParser.json())
+app.use(seneca.export('web'))
+app.use(Express.static('./public'))
app.listen(3000)
-
diff --git a/plugin-web/.eslintrc b/plugin-web/.eslintrc
new file mode 100644
index 0000000..b26e0fd
--- /dev/null
+++ b/plugin-web/.eslintrc
@@ -0,0 +1,4 @@
+{
+ "extends": ["seneca"]
+}
+
diff --git a/plugin-web/README.txt b/plugin-web/README.md
similarity index 88%
rename from plugin-web/README.txt
rename to plugin-web/README.md
index 621088d..b0cdf90 100644
--- a/plugin-web/README.txt
+++ b/plugin-web/README.md
@@ -1,5 +1,21 @@
-Notes:
+## Setup:
+```
+npm install
+```
+
+## Run:
+
+```
+npm run start
+```
+
+and then visit:
+```
+http://localhost:3000
+```
+
+## Notes:
The code in app.js shows you how to configure an express server using
custom seneca plugins for static page rendering, api communication, and
@@ -9,13 +25,13 @@ express app via app.use( seneca.export('web') ).
Each of the three plugins is housed in its own directory. Seneca plugins
export a function with a signature
-
+
function myPlugin( options ) { ... }
where options are passed from the call to seneca.use. Return a description object to give your plugin an explicit name. For example:
- return { name:'foo' }
-
+ return { name:'foo' }
+
When working with middleware plugins, use the role:web,use:[Function]
pattern to specify a middle function, acception the usual request,
response, and next arguments.
@@ -30,27 +46,16 @@ as middleware.
The api-plugin uses Express-like capabilities to map a RESTful API call to
an http response, using the seneca-web plugin.
-For more questions about creating your own custom plugins, check out
-http://senecajs.org/api.html#long-m-use.
-
To learn more about the seneca-web plugin, visit
https://github.com/rjrodger/seneca-web.
-Feel free to contact me on Twitter if you have any questions! :) @rjrodger
-
-
-
-Setup:
-
-npm install
+To learn more about plugins, visit :
+http://senecajs.org/plugins/#core-plugins
+Feel free to contact me on Twitter if you have any questions! :) @rjrodger
-Run with:
-node app.js
-and then visit:
-http://localhost:3000
diff --git a/plugin-web/api-plugin/index.js b/plugin-web/api-plugin/index.js
index ebeca56..152efcc 100644
--- a/plugin-web/api-plugin/index.js
+++ b/plugin-web/api-plugin/index.js
@@ -1,26 +1,22 @@
/* Copyright (c) 2010-2014 Richard Rodger, MIT License */
-"use strict";
-
-
-
-module.exports = function( options ) {
+'use strict'
+module.exports = function (options) {
// you need a middleware function to look for a matching URL
// export('web/httprouter') returns a router with Express-like capabilities
var router = this.export('web/httprouter')
- this.act('role:web',{use:router(function(app){
- app.get("/api/:action",function(req,res){
-
+ this.act('role:web', {use: router(function (app) {
+ app.get('/api/:action', function (req, res) {
// respond manually
- res.writeHead(200,{
+ res.writeHead(200, {
'Content-Type': 'application/json'
})
- res.end( JSON.stringify({action:req.params.action}) )
+ res.end(JSON.stringify({action: req.params.action}))
})
})})
// register this plugin with seneca
- return { name:'api' }
+ return { name: 'api' }
}
diff --git a/plugin-web/app.js b/plugin-web/app.js
index 4f6836d..38d7356 100644
--- a/plugin-web/app.js
+++ b/plugin-web/app.js
@@ -1,25 +1,22 @@
/* Copyright (c) 2013-2015 Richard Rodger, MIT License */
-"use strict";
-
+'use strict'
// use the http://expressjs.com web framework
-var express = require('express')
-var bodyParser = require('body-parser')
-var cookieParser = require('cookie-parser')
-var methodOverride = require('method-override')
+var Express = require('express')
+var BodyParser = require('body-parser')
+var CookieParser = require('cookie-parser')
+var MethodOverride = require('method-override')
// use https://github.com/substack/node-optimist for parsing the command line
var argv = require('optimist').argv
-
// setup the configuration
var conf = {
port: argv.p || 3000
}
-
// create a seneca instance
-var seneca = require('seneca')()
+var seneca = require('seneca')()
// use the example plugins
// they are all sub folders
@@ -27,28 +24,20 @@ seneca.use('./page-plugin')
seneca.use('./api-plugin')
seneca.use('./quick-plugin')
-
-
-
-
// set up express
-var app = express()
-app.use(cookieParser())
-app.use(express.query())
-app.use(bodyParser.urlencoded({extended: true}))
-app.use(methodOverride())
-app.use(bodyParser.json())
+var app = Express()
+app.use(CookieParser())
+app.use(Express.query())
+app.use(BodyParser.urlencoded({extended: true}))
+app.use(MethodOverride())
+app.use(BodyParser.json())
// this is the top level static content
-app.use(express.static(__dirname + '/public'))
+app.use(Express.static(__dirname + '/public'))
// add in the seneca middleware
// this is how the seneca plugins can respond to HTTP requests
-app.use( seneca.export('web') )
-
+app.use(seneca.export('web'))
// start the app!
app.listen(conf.port)
-
-
-
diff --git a/plugin-web/package.json b/plugin-web/package.json
index 285d967..c174677 100644
--- a/plugin-web/package.json
+++ b/plugin-web/package.json
@@ -4,12 +4,12 @@
"description": "Plugin web example",
"subdomain": "plugin-web-seneca-example",
"main": "app.js",
- "scripts": {
- "start": "app.js"
- },
"repository": "",
"author": "Richard Rodger",
"license": "MIT",
+ "scripts": {
+ "start": "node app.js"
+ },
"dependencies": {
"express": "~4.11.2",
"body-parser": "~1.11.0",
@@ -19,5 +19,10 @@
"seneca": "plugin",
"connect": "~3.3.4",
"serve-static": "~1.8.1"
+ },
+ "devDependencies": {
+ "eslint-config-seneca": "2.x.x",
+ "eslint-plugin-standard": "1.x.x",
+ "eslint-plugin-hapi": "4.x.x"
}
}
diff --git a/plugin-web/page-plugin/index.js b/plugin-web/page-plugin/index.js
index be0cc89..2fd5380 100644
--- a/plugin-web/page-plugin/index.js
+++ b/plugin-web/page-plugin/index.js
@@ -1,50 +1,41 @@
/* Copyright (c) 2010-2013 Richard Rodger, MIT License */
-"use strict";
+'use strict'
// use the connect module to deliver the static pages
-var connect = require('connect')
-var serveStatic = require('serve-static')
+var Connect = require('connect')
+var ServeStatic = require('serve-static')
-module.exports = function( options ) {
-
- // setup the options
- // by default, place this content under the /page URL
- // deepextend is a utility function that works like underscore.extend,
- // but is careful to recuresively extend also the internal structure of
- // properties that have objects as values.
+module.exports = function (options) {
+ /* setup the options
+ by default, place this content under the /page URL
+ deepextend is a utility function that works like underscore.extend,
+ but is careful to recuresively extend also the internal structure of
+ properties that have objects as values.*/
options = this.util.deepextend({
- prefix:'/page'
- },options)
+ prefix: '/page'
+ }, options)
// create a new connect app - this is separate from the main one in app.js
- var app = connect()
+ var app = Connect()
// just serve static content from the web folder
- app.use(serveStatic(__dirname+'/web'))
-
-
+ app.use(ServeStatic(__dirname + '/web'))
// you need a middleware function to trigger the local connect app
- this.act('role:web',{use:function(req,res,next) {
-
+ this.act('role:web', {use: function (req, res, next) {
// look for that URL prefix, by default /page
- if( 0 == req.url.indexOf(options.prefix) ) {
-
+ if(0 === req.url.indexOf(options.prefix)) {
// remove the prefix to avoid confusing the local connect app
req.url = req.url.substring(options.prefix.length)
-
// and delegate the work to the local connect app
- app( req, res, next )
+ app(req, res, next)
}
-
// else this request is nothing to do with us!
else next()
}})
-
-
// register this plugin with seneca
- return { name:'page' };
+ return { name: 'page' }
}
diff --git a/plugin-web/quick-plugin/index.js b/plugin-web/quick-plugin/index.js
index d610413..c61565d 100644
--- a/plugin-web/quick-plugin/index.js
+++ b/plugin-web/quick-plugin/index.js
@@ -1,18 +1,13 @@
/* Copyright (c) 2010-2014 Richard Rodger, MIT License */
-"use strict";
-
-
-
-module.exports = function( options ) {
+'use strict'
+module.exports = function (options) {
// you need a middleware function to look for a matching URL
- this.act('role:web',{use:function(req,res,next) {
-
+ this.act('role:web', {use: function (req, res, next) {
// look for a URL
- if( 0 == req.url.indexOf('/quick') ) {
-
+ if(0 === req.url.indexOf('/quick')) {
// respond manually
- res.writeHead(200,{
+ res.writeHead(200, {
'Content-Type': 'application/json'
})
res.end('{"data":"quick response!"}')
@@ -24,6 +19,5 @@ module.exports = function( options ) {
// register this plugin with seneca
- return { name:'quick' }
-
+ return { name: 'quick' }
}
diff --git a/shopping-cart/.eslintrc b/shopping-cart/.eslintrc
new file mode 100644
index 0000000..b26e0fd
--- /dev/null
+++ b/shopping-cart/.eslintrc
@@ -0,0 +1,4 @@
+{
+ "extends": ["seneca"]
+}
+
diff --git a/shopping-cart/README.txt b/shopping-cart/README.md
similarity index 91%
rename from shopping-cart/README.txt
rename to shopping-cart/README.md
index 577bab7..3e8d794 100644
--- a/shopping-cart/README.txt
+++ b/shopping-cart/README.md
@@ -1,5 +1,29 @@
-Notes:
+## Setup:
+```
+ npm install
+```
+
+## Run:
+```
+npm run start
+```
+
+and then visit:
+```
+http://localhost:3000
+```
+
+Access the admin panel on:
+```
+http://localhost:3000/admin
+```
+For debug db contents go to :
+```
+http://localhost:3000/mem-store/dump
+```
+
+## Notes:
This example shows the use of:
@@ -42,15 +66,4 @@ Feel free to contact me on Twitter if you have any questions! :) @rjrodger
-Run with:
-
-node app.js -p 3000
-
-and then visit:
-http://localhost:3000
-
-
-Access the admin panel on:
-http://localhost:3000/admin
-
diff --git a/shopping-cart/app.js b/shopping-cart/app.js
index f4995f6..4212209 100644
--- a/shopping-cart/app.js
+++ b/shopping-cart/app.js
@@ -1,33 +1,29 @@
/* Copyright (c) 2013-2015 Richard Rodger, MIT License */
-"use strict";
-
-
-var http = require('http')
-
-var express = require('express')
-var bodyParser = require('body-parser')
-var cookieParser = require('cookie-parser')
-var methodOverride = require('method-override')
-var session = require('express-session')
-var serveStatic = require('serve-static')
-var argv = require('optimist').argv
+'use strict'
+var Http = require('http')
+var Express = require('express')
+var BodyParser = require('body-parser')
+var CookieParser = require('cookie-parser')
+var MethodOverride = require('method-override')
+var ServeStatic = require('serve-static')
+var Argv = require('optimist').argv
var conf = {
- port: argv.p || 3000
+ port: Argv.p || 3000
}
-
// create a seneca instance
-var seneca = require('seneca')()
-
+var seneca = require('seneca')()
// enable the /mem-store/dump HTTP end point
// this lets you see the entire contents of the database as a JSON object
// in the browser - very useful for debugging!
-// Go to http://localhost:3333/mem-store/dump to debug db contents
-seneca.use('mem-store',{web:{dump:true}})
-
+// Go to http://localhost:3000/mem-store/dump to debug db contents
+if (seneca.version >= '2.0.0') {
+ seneca.use('entity')
+}
+seneca.use('mem-store', {web: {dump: true}})
// use the engage plugin to store extended user sessions
// these are known as "engagements"
@@ -35,30 +31,21 @@ seneca.use('mem-store',{web:{dump:true}})
// return the next day
seneca.use('engage')
-
-
// the shopping cart plugin provides standard web shopping cart business logic
// and also a HTTP JSON api
seneca.use('cart')
-
-
-
-
-
// set up express
-var app = express()
+var app = Express()
app.enable('trust proxy')
-app.use(cookieParser())
-app.use(express.query())
-app.use(bodyParser.urlencoded({extended: true}))
-app.use(methodOverride())
-app.use(bodyParser.json())
-
-app.use(serveStatic(__dirname + '/public'))
-
+app.use(CookieParser())
+app.use(Express.query())
+app.use(BodyParser.urlencoded({extended: true}))
+app.use(MethodOverride())
+app.use(BodyParser.json())
+app.use(ServeStatic(__dirname + '/public'))
// expose the shopping cart api
// the seneca.export('web') method returns a single function with the signature
@@ -66,94 +53,75 @@ app.use(serveStatic(__dirname + '/public'))
// this service method wraps up all the plugin HTTP endpoints
// seneca includes the connect utility plugin by default, which
// sets the special arguments req$ and res$ on all seneca calls, allowing
-// seneca actions to access the current HTTP req and res objects
-app.use( seneca.export('web') )
-
+// seneca actions to access the current HTTP req and res objects
+app.use(seneca.export('web'))
// express views for the cart pages
-app.engine('ejs',require('ejs-locals'))
+app.engine('ejs', require('ejs-locals'))
app.set('views', __dirname + '/views')
-app.set('view engine','ejs')
-
-
+app.set('view engine', 'ejs')
// a utility method
-function formatprice(price) {
- return '$' + (void 0 == price ? '0.00' : price.toFixed(2))
+function formatprice (price) {
+ return '$' + (void 0 === price ? '0.00' : price.toFixed(2))
}
-
-app.get('/', function(req,res,next) {
- req.seneca.act('role:cart,cmd:get',function(err,out) {
- if( err ) return next(err);
- res.render('index.ejs',{locals:{cart:out.cart,formatprice:formatprice}})
+app.get('/', function (req, res, next) {
+ req.seneca.act('role:cart,cmd:get', function (err, out) {
+ if (err) return next(err)
+ res.render('index.ejs', {locals: {cart: out.cart, formatprice: formatprice}})
})
})
-
-app.get('/cart', function(req,res,next){
- req.seneca.act('role:cart,cmd:get',function(err,out) {
- if( err ) return next(err);
- res.render('cart.ejs',{locals:{cart:out.cart,formatprice:formatprice}})
+app.get('/cart', function (req, res, next) {
+ req.seneca.act('role:cart,cmd:get', function (err, out) {
+ if(err) return next(err)
+ res.render('cart.ejs', {locals: {cart: out.cart, formatprice: formatprice}})
})
})
-
-app.get('/checkout', function(req,res,next){
- req.seneca.act('role:cart,cmd:get',function(err,out) {
- if( err ) return next(err);
- res.render('checkout.ejs',{locals:{cart:out.cart,formatprice:formatprice}})
+app.get('/checkout', function (req, res, next) {
+ req.seneca.act('role:cart,cmd:get', function (err, out) {
+ if(err) return next(err)
+ res.render('checkout.ejs', {locals: {cart: out.cart, formatprice: formatprice}})
})
})
-
// Use seneca.ready to ensure all plugins fully ready
// before we extend action patterns
-seneca.ready(function(){
-
+seneca.ready(function () {
// ensure that cart actions get the cart from the engagement
- seneca.wrap({role:'cart',cmd:'*'},function(args,done){
- var seneca = this
- var prior = this.prior
-
- if( !args.req$ ) return this.prior( args, done );
-
- this.act('role:engage,cmd:get,key:cart',function(err,out) {
- if( err ) return done(err);
-
+ seneca.wrap({role: 'cart', cmd: '*'}, function (args, done) {
+ var prior = this.prior
+ if(!args.req$) return this.prior(args, done)
+ this.act('role:engage,cmd:get,key:cart', function (err, out) {
+ if(err) return done(err)
args.cart = out.value
- prior( args, function(err,out) {
- if( err ) return done(err);
-
- this.act('role:engage,cmd:set,key:cart',{value:out.cart.id},function(err){
- if( err ) return done(err);
-
- done(null,out)
+ prior(args, function (err, out) {
+ if(err) return done(err)
+ this.act('role:engage,cmd:set,key:cart', {value: out.cart.id}, function (err) {
+ if(err) return done(err)
+ done(null, out)
})
})
})
})
})
-
-
// use the node.js http api to create a HTTP server
// this allows the admin plugin to use websockets
-var server = http.createServer(app)
+var server = Http.createServer(app)
server.listen(conf.port)
// unlike the user-accounts example, the local:true
// setting means anybody can access the admin panel from localhost
-seneca.use('data-editor',{admin:{local:true}})
-seneca.use('admin',{server:server,local:true})
+seneca.use('data-editor', {admin: {local: true}})
+seneca.use('admin', {server: server, local: true})
// set up some test products for the store
// create a product entity object
-var product_ent = seneca.make$('shop','product')
+var product_ent = seneca.make$('shop', 'product')
// create new product entities and save them
// (the $ suffix avoids namespace collisions with your own properties)
-product_ent.make$({name:'apple',price:1,code:'app01'}).save$()
-product_ent.make$({name:'orange',price:2,code:'ora02'}).save$()
-
-
-
+product_ent.make$({name: 'apple', price: 1, code: 'app01'}).save$()
+product_ent.make$({name: 'orange', price: 2, code: 'ora02'}).save$()
diff --git a/shopping-cart/package.json b/shopping-cart/package.json
index 6a5579b..79dc2b2 100644
--- a/shopping-cart/package.json
+++ b/shopping-cart/package.json
@@ -5,28 +5,34 @@
"subdomain": "shopping-cart-seneca-example",
"main": "app.js",
"scripts": {
- "start": "app.js"
+ "start": "node app.js -p 3000"
},
"repository": "",
"author": "Richard Rodger",
"license": "MIT",
"dependencies": {
- "body-parser": "~1.9.0",
- "cookie-parser": "~1.3.2",
- "ejs": "~1.0.0",
+ "body-parser": "~1.15.1",
+ "cookie-parser": "~1.4.2",
+ "ejs": "~2.4.2",
"ejs-locals": "~1.0.2",
- "express": "~4.9.5",
- "express-session": "~1.8.2",
- "method-override": "~2.2.0",
+ "express": "~4.13.4",
+ "express-session": "~1.13.0",
+ "method-override": "~2.3.6",
"optimist": "~0.6.1",
"seneca": "plugin",
+ "seneca-entity": "0.1.1",
"seneca-admin": "~0.2.0",
- "seneca-auth": "~0.4.0",
+ "seneca-auth": "~1.0.1",
"seneca-cart": "~0.2.0",
"seneca-data-editor": "~0.2.0",
"seneca-engage": "~0.3.1",
"seneca-jsonrest-api": "~0.3.1",
- "seneca-user": "~0.2.10",
- "serve-static": "~1.6.3"
+ "seneca-user": "~1.0.2",
+ "serve-static": "~1.10.2"
+ },
+ "devDependencies": {
+ "eslint-config-seneca": "2.x.x",
+ "eslint-plugin-standard": "1.x.x",
+ "eslint-plugin-hapi": "4.x.x"
}
}
diff --git a/shopping-cart/public/js/shopping-cart.js b/shopping-cart/public/js/shopping-cart.js
index 8225f5d..9f00710 100644
--- a/shopping-cart/public/js/shopping-cart.js
+++ b/shopping-cart/public/js/shopping-cart.js
@@ -5,14 +5,14 @@ $(function(){
ora02:$('#ora02'),
}
- var prod_form = $('#prod_form')
+ var prod_form = $('#prod_form')
var code_input = $('#code_input')
- var cart_form = $('#cart_form')
+ var cart_form = $('#cart_form')
var entry_input = $('#entry_input')
- for( var code in prodbox ) {
- prodbox[code].click(function(){
+ for(var code in prodbox) {
+ prodbox[code].click(function () {
var box = $(this)
code_input.val(box.attr('id'))
prod_form.submit()
@@ -25,4 +25,4 @@ $(function(){
entry_input.val(entry)
cart_form.submit()
})
-})
\ No newline at end of file
+})
diff --git a/shopping-cart/views/cart.ejs b/shopping-cart/views/cart.ejs
index 07db105..f722ec1 100644
--- a/shopping-cart/views/cart.ejs
+++ b/shopping-cart/views/cart.ejs
@@ -1,42 +1,30 @@
<% layout('layout') -%>
-
Cart
-
-<% if( !cart ) { %>
-
-Nothing in your cart.
-
-<% } else { %>
-
-
-<% var entries = cart.entries || []
- for( var i = 0; i < entries.length; i++ ) {
- var entry = entries[i]
-%>
-
-| <%-entry.name%> |
-<%-formatprice(entry.price)%> |
-remove |
-
-<% } %>
-
-
-
-| Total |
-<%-formatprice(cart.total)%> |
-
-
-
-<% } %>
-
-
-
-checkout!
-
-
-buy more!
-
-
-
+<% if( !cart ) { %>
+ Nothing in your cart.
+ <% } else { %>
+
+ <% var entries = cart.entries || []
+ for( var i = 0; i < entries.length; i++ ) {
+ var entry = entries[i]
+ %>
+
+ | <%-entry.name%> |
+ <%-formatprice(entry.price)%> |
+ remove |
+
+ <% } %>
+
+ | Total |
+ <%-formatprice(cart.total)%> |
+
+
+ <% } %>
+
+ checkout!
+
+
+ buy more!
+
diff --git a/shopping-cart/views/checkout.ejs b/shopping-cart/views/checkout.ejs
index ff861ba..810096a 100644
--- a/shopping-cart/views/checkout.ejs
+++ b/shopping-cart/views/checkout.ejs
@@ -3,35 +3,26 @@
Checkout
<% if( !cart ) { %>
-
-Nothing in your cart.
-buy something
-
-<% } else { %>
-
-
-<% var entries = cart.entries || []
- for( var i = 0; i < entries.length; i++ ) {
- var entry = entries[i]
-%>
-
-| <%-entry.name%> |
-<%-formatprice(entry.price)%> |
-
-<% } %>
-
-
-| Total |
-<%-cart.total%> |
-
-
-
-
-
-
-
-<% } %>
-
-
-
-cancel
+
+ Nothing in your cart.
+ buy something
+
+ <% } else { %>
+
+ <% var entries = cart.entries || []
+ for( var i = 0; i < entries.length; i++ ) {
+ var entry = entries[i]
+ %>
+
+ | <%-entry.name%> |
+ <%-formatprice(entry.price)%> |
+
+ <% } %>
+
+ | Total |
+ <%-cart.total%> |
+
+
+ <% } %>
+
+ cancel
diff --git a/shopping-cart/views/index.ejs b/shopping-cart/views/index.ejs
index 703002b..a4e986e 100644
--- a/shopping-cart/views/index.ejs
+++ b/shopping-cart/views/index.ejs
@@ -6,7 +6,7 @@
Buy an Orange!
diff --git a/shopping-cart/views/layout.ejs b/shopping-cart/views/layout.ejs
index 9faee4c..728ad90 100644
--- a/shopping-cart/views/layout.ejs
+++ b/shopping-cart/views/layout.ejs
@@ -1,12 +1,12 @@
-
-
-
+
+
+
-<%- body %>
+ <%- body %>
diff --git a/simple-plugin/.eslintrc b/simple-plugin/.eslintrc
new file mode 100644
index 0000000..b26e0fd
--- /dev/null
+++ b/simple-plugin/.eslintrc
@@ -0,0 +1,4 @@
+{
+ "extends": ["seneca"]
+}
+
diff --git a/simple-plugin/README.md b/simple-plugin/README.md
index bbe4190..00eea9a 100644
--- a/simple-plugin/README.md
+++ b/simple-plugin/README.md
@@ -1,9 +1,29 @@
-For an introduction to Seneca data entities, please read the
-[senecajs.org tutorial](http://senecajs.org/data-entities.html).
+## Setup:
+```
+ npm install
+```
+
+## Run:
+```
+ npm run start
+```
+This shows a very common use case for loading and running Seneca
+plugins.
+
+
+For detailed logging, try:
+```
+ npm run details
+```
+To run as a micro-service, see micro-service.js
+## Test:
+```
+npm run test
+```
-Notes:
+## Notes:
The code in simple.js shows you how to create a simple plugin. Plugins
are just a way to organise your action patterns into groups so that
@@ -38,23 +58,9 @@ level. These lof entries will be annotated with the name of the plugin
and the id of the current action, so match them up against other
actions.
+For an introduction to Seneca data entities, please read the
+[senecajs.org tutorial](http://senecajs.org/tutorials/understanding-data-entities.html).
-Setup:
-$ npm install
-
-
-Run with:
-$ node main.js
-
-This shows a very common use case for loading and running Seneca
-plugins.
-
-
-For detailed logging, try:
-$ node main.js --seneca.log.all
-
-
-To run as a micro-service, see micro-service.js
diff --git a/simple-plugin/package.json b/simple-plugin/package.json
index f5f6c3e..11720c2 100644
--- a/simple-plugin/package.json
+++ b/simple-plugin/package.json
@@ -4,7 +4,9 @@
"description": "Simple plugin example",
"main": "simple.js",
"scripts": {
- "test": "./node_modules/.bin/mocha test/*.test.js"
+ "test": "./node_modules/.bin/mocha test/*.test.js",
+ "start": "node main.js",
+ "details":"node main.js --seneca.log.all"
},
"author": "Richard Rodger (http://richardrodger.com)",
"license": "MIT",
@@ -13,5 +15,10 @@
},
"dependencies": {
"seneca": "plugin"
+ },
+ "devDependencies": {
+ "eslint-config-seneca": "2.x.x",
+ "eslint-plugin-standard": "1.x.x",
+ "eslint-plugin-hapi": "4.x.x"
}
}
diff --git a/simple-plugin/simple.js b/simple-plugin/simple.js
index 64822fc..352be35 100644
--- a/simple-plugin/simple.js
+++ b/simple-plugin/simple.js
@@ -1,29 +1,22 @@
-"use strict";
+'use strict'
-module.exports = function simple( options ) {
+module.exports = function simple (options) {
var seneca = this
-
var suffix = ''
-
seneca.add('role:simple,cmd:foo', cmd_foo)
-
seneca.add('init:simple', init)
-
- function cmd_foo( args, done ) {
- done( null, {text:'foo-'+args.text+suffix} )
+ function cmd_foo (args, done) {
+ done(null, {text: 'foo-' + args.text + suffix})
}
-
- function init( args, done ) {
+ function init (args, done) {
var seneca = this
- seneca.log.info("preparing something...")
-
- setTimeout( function() {
+ seneca.log.info('preparing something...')
+ setTimeout(function () {
suffix = '-zed'
- seneca.log.info("ready!")
+ seneca.log.info('ready!')
done()
- }, 111 )
+ }, 111)
}
-
}
diff --git a/simple-plugin/test/simple.test.js b/simple-plugin/test/simple.test.js
index 2d60b66..586584b 100644
--- a/simple-plugin/test/simple.test.js
+++ b/simple-plugin/test/simple.test.js
@@ -1,23 +1,17 @@
-"use strict";
-
-var assert = require('assert')
-
-var seneca = require('seneca')
-
-
-describe('simple', function(){
-
- it('happy', function( fin){
-
- seneca({log:'silent',errhandler:fin})
- .use('..')
- .act('role:simple,cmd:foo,text:red',
- function( err, out ) {
- if( err ) return fin(err);
-
- assert.equal( out.text, 'foo-red-zed' )
- fin()
- })
+'use strict'
+
+var Assert = require('assert')
+var Seneca = require('seneca')
+
+describe('simple', function () {
+ it('happy', function (fin) {
+ Seneca({log: 'silent', errhandler: fin})
+ .use('..')
+ .act('role:simple,cmd:foo,text:red',
+ function (err, out) {
+ if(err) return fin(err)
+ Assert.equal(out.text, 'foo-red-zed')
+ fin()
+ })
})
-
})
diff --git a/user-accounts/.eslintrc b/user-accounts/.eslintrc
new file mode 100644
index 0000000..b26e0fd
--- /dev/null
+++ b/user-accounts/.eslintrc
@@ -0,0 +1,4 @@
+{
+ "extends": ["seneca"]
+}
+
diff --git a/user-accounts/README.txt b/user-accounts/README.md
similarity index 73%
rename from user-accounts/README.txt
rename to user-accounts/README.md
index 331d5fe..56b7812 100644
--- a/user-accounts/README.txt
+++ b/user-accounts/README.md
@@ -1,5 +1,32 @@
+## Setup:
+```
+ npm install
+```
-Notes:
+## Run:
+```
+npm run start
+```
+
+Then visit:
+```
+http://localhost:3000
+```
+Access the admin panel on:
+```
+http://localhost:3000/admin
+```
+
+Or to use a custom port:
+```
+node app.js --seneca.options.main.port=4000
+```
+## Create config:
+
+Copy config.template.js to config.mine.js
+Optionally add keys for Twitter and Facebook OAuth
+
+## Notes:
This example shows the usage of:
@@ -10,7 +37,7 @@ This example shows the usage of:
An express server serves the static register page as the starting-point
of the example. The registration functionality is handled by the seneca-auth
-plugin, which takes the requests to 'auth/*', verifies the inputs, and redirects to the account page.
+plugin, which takes the requests to 'auth/, verifies the inputs, and redirects to the account page.
The multi-page app login shows how to use ejs templates and the seneca-auth
plugin to verify users and conditionally redirect on verification. A few
@@ -26,34 +53,13 @@ options are available by creating a config.mine.js file with Twitter and
Facebook OAuth keys. seneca-auth uses these keys to authenticate the user,
using the same pattern as regular user authentication.
-For more questions about the seneca-auth plugin, check out
-https://github.com/rjrodger/seneca-auth
+For more questions about the seneca-auth plugin, check out [here]
+(https://github.com/rjrodger/seneca-auth)
-To learn more about the seneca.pin() method, check out
-http://senecajs.org/api.html#long-m-pin (more documentation soon)
+To learn more about the seneca.pin() method, check out [pin-pattern]
+(http://senecajs.org/api/#pin-pin-pattern-)
Feel free to contact me on Twitter if you have any questions! :) @rjrodger
-
-
-Create config:
-
-Copy config.template.js to config.mine.js
-Optionally add keys for Twitter and Facebook OAuth
-
-Run with:
-
-$ node app.js
-
-Or to use a custom port:
-$ node app.js --seneca.options.main.port=4000
-
-Then visit:
-http://localhost:3000
-
-Access the admin panel on:
-http://localhost:3000/admin
-
-
diff --git a/user-accounts/app.js b/user-accounts/app.js
index aba0097..470e25a 100644
--- a/user-accounts/app.js
+++ b/user-accounts/app.js
@@ -1,17 +1,15 @@
/* Copyright (c) 2012-2015 Richard Rodger, MIT License */
-"use strict";
+'use strict'
-var http = require('http')
-
-var express = require('express')
-var bodyParser = require('body-parser')
-var cookieParser = require('cookie-parser')
-var methodOverride = require('method-override')
-var session = require('express-session')
-var serveStatic = require('serve-static')
-var argv = require('optimist').argv
+var Http = require('http')
+var Express = require('express')
+var BodyParser = require('body-parser')
+var CookieParser = require('cookie-parser')
+var MethodOverride = require('method-override')
+var Session = require('express-session')
+var ServeStatic = require('serve-static')
// create a seneca instance
var seneca = require('seneca')()
@@ -21,84 +19,73 @@ var seneca = require('seneca')()
// copy template config.template.js to config.mine.js and customize
var options = seneca.options('config.mine.js')
-
// use the user and auth plugins
// the user plugin gives you user account business logic
seneca.use('user')
-
// the auth plugin handles HTTP authentication
-seneca.use('auth',{
+seneca.use('auth', {
// redirects after login are needed for traditional multi-page web apps
- redirect:{
+ redirect: {
login: {
- win: '/account',
+ win: '/account',
fail: '/login#failed'
},
register: {
- win: '/account',
+ win: '/account',
fail: '/#failed'
}
}
})
-
// use the express module in the normal way
-var app = express()
+var app = Express()
app.enable('trust proxy')
-app.use(cookieParser())
-app.use(express.query())
-app.use(bodyParser.urlencoded({extended: true}))
-app.use(methodOverride())
-app.use(bodyParser.json())
+app.use(CookieParser())
+app.use(Express.query())
+app.use(BodyParser.urlencoded({extended: true}))
+app.use(MethodOverride())
+app.use(BodyParser.json())
// Use in-memory sessions so OAuth will work
// In production, use redis or similar
-app.use(session({secret:'seneca'}))
-
-app.use(serveStatic(__dirname + '/public'))
-
+app.use(Session({secret: 'seneca'}))
+app.use(ServeStatic(__dirname + '/public'))
// add seneca middleware
-app.use( seneca.export('web') )
-
+app.use(seneca.export('web'))
// some express views
-app.engine('ejs',require('ejs-locals'))
+app.engine('ejs', require('ejs-locals'))
app.set('views', __dirname + '/views')
-app.set('view engine','ejs')
+app.set('view engine', 'ejs')
-app.get('/login', function(req, res){
- res.render('login.ejs',{})
+app.get('/login', function (req, res) {
+ res.render('login.ejs', {})
})
// when rendering the account page, use the req.seneca.user object
// to get user details. This is automatically set up by the auth plugin
-app.get('/account', function(req, res){
- res.render('account.ejs',{locals:{user:req.seneca.user}})
+app.get('/account', function (req, res) {
+ res.render('account.ejs', {locals: {user: req.seneca.user}})
})
-
-
// create some test accounts
-// the "pin" creates a more convenient api, avoiding the need for
+// the "pin" creates a more convenient api, avoiding the need for
// a full action specification: seneca.act( {role:'user', cmd:'register', ... } )
-var u = seneca.pin({role:'user',cmd:'*'})
-u.register({nick:'u1',name:'nu1',email:'u1@example.com',password:'u1',active:true})
+var u = seneca.pin({role: 'user', cmd: '*'})
+u.register({nick: 'u1', name: 'nu1', email: 'u1@example.com', password: 'u1', active: true})
u.register({nick:'u2',name:'nu2',email:'u2@example.com',password:'u2',active:true})
-u.register({nick:'a1',name:'na1',email:'a1@example.com',password:'a1',active:true,admin:true})
-
-
+u.register({nick: 'a1', name: 'na1', email: 'a1@example.com', password: 'a1', active: true, admin: true})
// create a HTTP server using the core Node API
// this lets the admin plugin use web sockets
-var server = http.createServer(app)
-server.listen( options.main ? options.main.port : 3000 )
+var server = Http.createServer(app)
+server.listen(options.main ? options.main.port : 3000)
// visit http://localhost[:port]/admin to see the admin page
// you'll need to logged in as an admin - user 'a1' above
seneca.use('data-editor')
-seneca.use('admin',{server:server})
-
+seneca.use('admin', {server: server})
diff --git a/user-accounts/config.template.js b/user-accounts/config.template.js
index a998610..3991c5c 100644
--- a/user-accounts/config.template.js
+++ b/user-accounts/config.template.js
@@ -6,14 +6,14 @@ module.exports = {
auth: {
service: {
twitter: {
- key: "TWITTER_KEY",
- secret: "TWITTER_SECRET",
- urlhost: "http://localhost:3000"
+ key: 'TWITTER_KEY',
+ secret: 'TWITTER_SECRET',
+ urlhost: 'http://localhost:3000'
},
facebook: {
- key: "FACEBOOK_ID",
- secret: "FACEBOOK_SECRET",
- urlhost: "http://localhost:3000"
+ key: 'FACEBOOK_ID',
+ secret: 'FACEBOOK_SECRET',
+ urlhost: 'http://localhost:3000'
}
}
}
diff --git a/user-accounts/package.json b/user-accounts/package.json
index a333084..a5f31d5 100644
--- a/user-accounts/package.json
+++ b/user-accounts/package.json
@@ -5,27 +5,33 @@
"subdomain": "user-accounts-seneca-example",
"main": "app.js",
"scripts": {
- "start": "app.js"
+ "start": "node app.js"
},
"repository": "",
"author": "Richard Rodger",
"license": "MIT",
"dependencies": {
- "express": "~4.9.5",
- "body-parser": "~1.9.0",
- "cookie-parser": "~1.3.2",
- "method-override": "~2.2.0",
- "express-session": "~1.8.2",
- "serve-static": "~1.6.3",
+ "express": "~4.13.4",
+ "body-parser": "~1.15.1",
+ "cookie-parser": "~1.4.2",
+ "method-override": "~2.3.6",
+ "express-session": "~1.13.0",
+ "serve-static": "~1.10.2",
"optimist": "~0.6.1",
- "ejs": "~1.0.0",
+ "ejs": "~2.4.1",
"ejs-locals": "~1.0.2",
+ "node-uuid": "~1.4.0",
"seneca": "plugin",
- "seneca-user": "~0.2.10",
- "seneca-auth": "~0.4.0",
+ "seneca-user": "~1.0.1",
+ "seneca-auth": "~1.0.1",
"seneca-admin": "~0.2.0",
"seneca-jsonrest-api": "~0.3.1",
- "seneca-perm": "~0.4.0",
+ "seneca-perm": "~0.5.6",
"seneca-data-editor": "~0.2.0"
+ },
+ "devDependencies": {
+ "eslint-config-seneca": "2.x.x",
+ "eslint-plugin-standard": "1.x.x",
+ "eslint-plugin-hapi": "4.x.x"
}
}
diff --git a/user-accounts/public/js/user-accounts.js b/user-accounts/public/js/user-accounts.js
index 8e143c0..370cc27 100644
--- a/user-accounts/public/js/user-accounts.js
+++ b/user-accounts/public/js/user-accounts.js
@@ -13,15 +13,13 @@ $(function(){
http.post('/auth/logout',{},showLogin)
})
-
http.get('/auth/instance',showAccount)
})
+function showAccount (err, instance) {
+ if(err) return console.log(err)
-function showAccount(err,instance) {
- if( err ) return console.log(err);
-
- if( instance.user ) {
+ if(instance.user) {
$('#user_name').text(instance.user.name)
$('#user_email').text(instance.user.email)
@@ -30,9 +28,9 @@ function showAccount(err,instance) {
}
}
-function showLogin(err) {
- if( err ) return console.log(err);
+function showLogin (err) {
+ if(err) return console.log(err)
$('#content_login').slideDown()
$('#content_account').slideUp()
-}
\ No newline at end of file
+}