UNPKG

2.82 kBJavaScriptView Raw
1var async = require('async')
2var lodash = require('lodash')
3var errback = require('serialize-error')
4var isArray = lodash.isArray
5var isFunction = lodash.isFunction
6var reject = lodash.reject
7
8function lambda() {
9
10 var firstRun = true // important to keep this here in this closure
11 var args = [].slice.call(arguments, 0) // grab the args
12
13 // fail loudly for programmer not passing anything
14 if (args.length === 0) {
15 throw Error('lambda requires at least one callback function')
16 }
17
18 // check for lambda([], (err, result)=>) sig
19 var customFormatter = isArray(args[0]) && isFunction(args[1])
20 var fmt = customFormatter? args[1] : false
21 var fns = fmt? args[0] : args
22
23 // we only deal in function values around here
24 var notOnlyFns = reject(fns, isFunction).length > 0
25 if (notOnlyFns) {
26 throw Error('bad argument found: lambda(...fns) or lambda([...],(err, result)=>)')
27 }
28
29 // returns a lambda sig
30 return function(event, context) {
31
32 // this is to avoid warm start (sometimes lambda containers are cached … yeaaaaah.)
33 if (firstRun) {
34 fns.unshift(function(callback) {
35 callback(null, event)
36 })
37 firstRun = false
38 }
39 else {
40 // mutates! wtf. remove the cached callback
41 fns.shift()
42 // add the fresh event
43 fns.unshift(function(callback) {
44 callback(null, event)
45 })
46 }
47
48 // asummptions:
49 // - err should be an array of Errors
50 // - because lambda deals in json we need to serialize them
51 function formatter(err, result) {
52 if (fmt) {
53 fmt(err, result, context)
54 }
55 else {
56 if (err) {
57 result = {
58 ok: false,
59 errors: (isArray(err)? err : [err]).map(errback)
60 }
61 }
62 else {
63 if (typeof result === 'undefined') result = {}
64 result.ok = true
65 }
66 // deliberate use context.succeed;
67 // there is no (good) use case for the (current) context.fail behavior
68 // (but happy to discuss in an issue)!
69 context.succeed(result)
70 }
71 }
72
73 // the real worker here
74 async.waterfall(fns, formatter)
75 }
76}
77
78/**
79 * var lambda = require('@mallwins/lambda')
80 *
81 * var fn = lambda(function (event, data) {
82 * callback(null, {hello:'world'})
83 * })
84 *
85 * // fake run locally
86 * lambda.local(fn, fakeEvent, function done(err, result) {
87 * if (err) {
88 * console.error(err)
89 * }
90 * else {
91 * console.log(result) // logs: {ok:true, hello:'world'}
92 * }
93 * })
94 */
95lambda.local = function offlineInvoke(fn, event, callback) {
96 var context = {
97 succeed: function offlineSucceed(x) {
98 if (x.ok) {
99 callback(null, x)
100 }
101 else {
102 callback(x.errors)
103 }
104 }
105 }
106 fn(event, context)
107}
108
109module.exports = lambda