'use strict'; const BbPromise = require('bluebird'); const _ = require('lodash'); const path = require('path'); const validate = require('../lib/validate'); class AwsInvokeLocal { constructor(serverless, options) { this.serverless = serverless; this.options = options || {}; this.provider = this.serverless.getProvider('aws'); Object.assign(this, validate); this.hooks = { 'invoke:local:invoke': () => BbPromise.bind(this) .then(this.extendedValidate) .then(this.loadEnvVars) .then(this.invokeLocal), }; } extendedValidate() { this.validate(); // validate function exists in service this.options.functionObj = this.serverless.service.getFunction(this.options.function); // if data is provided via CLI, sanitize it if (typeof this.options.data === 'string') { try { this.options.data = JSON.parse(this.options.data); } catch (exception) { // do nothing if it's a simple string } } // if path is provided, load data from path if (this.options.path) { const absolutePath = path.isAbsolute(this.options.path) ? this.options.path : path.join(this.serverless.config.servicePath, this.options.path); if (!this.serverless.utils.fileExistsSync(absolutePath)) { throw new this.serverless.classes.Error('The file you provided does not exist.'); } this.options.data = this.serverless.utils.readFileSync(absolutePath); } return BbPromise.resolve(); } loadEnvVars() { const providerEnvVars = this.serverless.service.provider.environment || {}; const functionEnvVars = this.options.functionObj.environment || {}; _.merge(process.env, providerEnvVars, functionEnvVars); return BbPromise.resolve(); } invokeLocal() { const runtime = this.options.functionObj.runtime || this.serverless.service.provider.runtime || 'nodejs4.3'; const handler = this.options.functionObj.handler; const handlerPath = handler.split('.')[0]; const handlerName = handler.split('.')[1]; if (runtime === 'nodejs4.3') { return this.invokeLocalNodeJs( handlerPath, handlerName, this.options.data); } throw new this.serverless.classes .Error('You can only invoke Node.js functions locally.'); } invokeLocalNodeJs(handlerPath, handlerName, event) { let lambda; try { /* * we need require() here to load the handler from the file system * which the user has to supply by passing the function name */ lambda = require(path // eslint-disable-line global-require .join(this.serverless.config.servicePath, handlerPath))[handlerName]; } catch (error) { this.serverless.cli.consoleLog(error); process.exit(0); } const callback = (err, result) => { if (err) { throw err; } else { if (result) { this.serverless.cli.consoleLog(JSON.stringify(result, null, 4)); } process.exit(0); } }; const context = { awsRequestId: 'id', invokeid: 'id', logGroupName: this.provider.naming.getLogGroupName(this.options.functionObj.name), logStreamName: '2015/09/22/[HEAD]13370a84ca4ed8b77c427af260', functionVersion: 'HEAD', isDefaultFunctionVersion: true, functionName: this.options.functionObj.name, memoryLimitInMB: '1024', succeed(result) { return callback(null, result); }, fail(error) { return callback(error); }, done() { return callback(); }, getRemainingTimeInMillis() { return 5000; }, }; return lambda(event, context, callback); } } module.exports = AwsInvokeLocal;