<commit_before>'use strict';

const { exec } = require('child_process');
const path = require('path');
const ApiGateway = require('./ApiGateway');
const ApiGatewayWebSocket = require('./ApiGatewayWebSocket');
const debugLog = require('./debugLog');
const functionHelper = require('./functionHelper');
const { createDefaultApiKey, satisfiesVersionRange } = require('./utils');
const { CUSTOM_OPTION, supportedRuntimes } = require('./config/index.js');
const { peerDependencies } = require('../package.json');

module.exports = class ServerlessOffline {
  constructor(serverless, options) {
    this.serverless = serverless;
    this.service = serverless.service;
    this.serverlessLog = serverless.cli.log.bind(serverless.cli);
    this.options = options;
    this.exitCode = 0;
    this._experimentalWarningNotified = false;

    this.commands = {
      offline: {
        // add start nested options
        commands: {
          start: {
            lifecycleEvents: ['init', 'end'],
            usage:
              'Simulates API Gateway to call your lambda functions offline using backward compatible initialization.',
          },
        },
        lifecycleEvents: ['start'],
        options: {
          apiKey: {
            usage:
              'Defines the API key value to be used for endpoints marked as private. Defaults to a random hash.',
          },
          binPath: {
            shortcut: 'b',
            usage: 'Path to the Serverless binary.',
          },
          cacheInvalidationRegex: {
            usage:
              'Provide the plugin with a regexp to use for cache invalidation. Default: node_modules',
          },
          corsAllowHeaders: {
            usage:
              'Used to build the Access-Control-Allow-Headers header for CORS support.',
          },
          corsAllowOrigin: {
            usage:
              'Used to build the Access-Control-Allow-Origin header for CORS support.',
          },
          corsDisallowCredentials: {
            usage:
              'Used to override the Access-Control-Allow-Credentials default (which is true) to false.',
          },
          corsExposedHeaders: {
            usage:
              'USed to build the Access-Control-Exposed-Headers response header for CORS support',
          },
          disableCookieValidation: {
            usage: 'Used to disable cookie-validation on hapi.js-server',
          },
          enforceSecureCookies: {
            usage: 'Enforce secure cookies',
          },
          exec: {
            usage:
              'When provided, a shell script is executed when the server starts up, and the server will shut down after handling this command.',
          },
          hideStackTraces: {
            usage: 'Hide the stack trace on lambda failure. Default: false',
          },
          host: {
            shortcut: 'o',
            usage: 'The host name to listen on. Default: localhost',
          },
          httpsProtocol: {
            shortcut: 'H',
            usage:
              'To enable HTTPS, specify directory (relative to your cwd, typically your project dir) for both cert.pem and key.pem files.',
          },
          location: {
            shortcut: 'l',
            usage: "The root location of the handlers' files.",
          },
          noAuth: {
            usage: 'Turns off all authorizers',
          },
          noEnvironment: {
            usage:
              'Turns off loading of your environment variables from serverless.yml. Allows the usage of tools such as PM2 or docker-compose.',
          },
          noTimeout: {
            shortcut: 't',
            usage: 'Disables the timeout feature.',
          },
          port: {
            shortcut: 'P',
            usage: 'Port to listen on. Default: 3000',
          },
          prefix: {
            shortcut: 'p',
            usage:
              'Adds a prefix to every path, to send your requests to http://localhost:3000/prefix/[your_path] instead.',
          },
          preserveTrailingSlash: {
            usage: 'Used to keep trailing slashes on the request path',
          },
          printOutput: {
            usage: 'Outputs your lambda response to the terminal.',
          },
          providedRuntime: {
            usage: 'Sets the provided runtime for lambdas',
          },
          region: {
            shortcut: 'r',
            usage: 'The region used to populate your templates.',
          },
          resourceRoutes: {
            usage:
              'Turns on loading of your HTTP proxy settings from serverless.yml.',
          },
          showDuration: {
            usage: 'Show the execution time duration of the lambda function.',
          },
          skipCacheInvalidation: {
            shortcut: 'c',
            usage:
              'Tells the plugin to skip require cache invalidation. A script reloading tool like Nodemon might then be needed',
          },
          stage: {
            shortcut: 's',
            usage: 'The stage used to populate your templates.',
          },
          useSeparateProcesses: {
            usage: 'Uses separate node processes for handlers',
          },
          websocketPort: {
            usage: 'Websocket port to listen on. Default: 3001',
          },
        },
        usage: 'Simulates API Gateway to call your lambda functions offline.',
      },
    };

    this.hooks = {
      'offline:start:init': this.start.bind(this),
      'offline:start': this.startWithExplicitEnd.bind(this),
      'offline:start:end': this.end.bind(this),
    };
  }

  printBlankLine() {
    console.log();
  }

  logPluginIssue() {
    this.serverlessLog(
      'If you think this is an issue with the plugin please submit it, thanks!',
    );
    this.serverlessLog('https://github.com/dherault/serverless-offline/issues');
  }

  // Entry point for the plugin (sls offline) when running 'sls offline start'
  start() {
    this._verifyServerlessVersionCompatibility();

    // Some users would like to know their environment outside of the handler
    process.env.IS_OFFLINE = true;

    return Promise.resolve(this._buildServer())
      .then(() => this.apiGateway._listen())
      .then(() => this.hasWebsocketRoutes && this.apiGatewayWebSocket._listen())
      .then(() =>
        this.options.exec
          ? this._executeShellScript()
          : this._listenForTermination(),
      );
  }

  /**
   * Entry point for the plugin (sls offline) when running 'sls offline'
   * The call to this.end() would terminate the process before 'offline:start:end' could be consumed
   * by downstream plugins. When running sls offline that can be expected, but docs say that
   * 'sls offline start' will provide the init and end hooks for other plugins to consume
   * */
  startWithExplicitEnd() {
    return this.start().then(() => this.end());
  }

  _listenForTermination() {
    // SIGINT will be usually sent when user presses ctrl+c
    const waitForSigInt = new Promise((resolve) => {
      process.on('SIGINT', () => resolve('SIGINT'));
    });

    // SIGTERM is a default termination signal in many cases,
    // for example when "killing" a subprocess spawned in node
    // with child_process methods
    const waitForSigTerm = new Promise((resolve) => {
      process.on('SIGTERM', () => resolve('SIGTERM'));
    });

    return Promise.race([waitForSigInt, waitForSigTerm]).then((command) => {
      this.serverlessLog(`Got ${command} signal. Offline Halting...`);
    });
  }

  _executeShellScript() {
    const command = this.options.exec;
    const options = {
      env: {
        IS_OFFLINE: true,
        ...this.service.provider.environment,
        ...this.originalEnvironment,
      },
    };

    this.serverlessLog(`Offline executing script [${command}]`);

    return new Promise((resolve) => {
      exec(command, options, (error, stdout, stderr) => {
        this.serverlessLog(`exec stdout: [${stdout}]`);
        this.serverlessLog(`exec stderr: [${stderr}]`);

        if (error) {
          // Use the failed command's exit code, proceed as normal so that shutdown can occur gracefully
          this.serverlessLog(`Offline error executing script [${error}]`);
          this.exitCode = error.code || 1;
        }
        resolve();
      });
    });
  }

  _buildServer() {
    // Methods
    this._setOptions(); // Will create meaningful options from cli options
    this._storeOriginalEnvironment(); // stores the original process.env for assigning upon invoking the handlers

    this.apiGateway = new ApiGateway(
      this.serverless,
      this.options,
      this.velocityContextOptions,
    );

    const server = this.apiGateway._createServer();

    this.hasWebsocketRoutes = false;
    this.apiGatewayWebSocket = new ApiGatewayWebSocket(
      this.serverless,
      this.options,
    );
    this.apiGatewayWebSocket._createWebSocket();

    this._setupEvents();
    this.apiGateway._createResourceRoutes(); // HTTP Proxy defined in Resource
    this.apiGateway._create404Route(); // Not found handling

    return server;
  }

  _storeOriginalEnvironment() {
    this.originalEnvironment = { ...process.env };
  }

  _setOptions() {
    // Merge the different sources of values for this.options
    // Precedence is: command line options, YAML options, defaults.
    const defaultOptions = {
      apiKey: createDefaultApiKey(),
      cacheInvalidationRegex: 'node_modules',
      corsAllowOrigin: '*',
      corsAllowCredentials: true,
      corsAllowHeaders: 'accept,content-type,x-api-key,authorization',
      corsExposedHeaders: 'WWW-Authenticate,Server-Authorization',
      disableCookieValidation: false,
      enforceSecureCookies: false,
      exec: '',
      hideStackTraces: false,
      host: 'localhost',
      httpsProtocol: '',
      location: '.',
      noAuth: false,
      noEnvironment: false,
      noTimeout: false,
      port: 3000,
      prefix: '/',
      preserveTrailingSlash: false,
      printOutput: false,
      providedRuntime: '',
      showDuration: false,
      stage: this.service.provider.stage,
      region: this.service.provider.region,
      resourceRoutes: false,
      skipCacheInvalidation: false,
      useSeparateProcesses: false,
      websocketPort: 3001,
    };

    // In the constructor, stage and regions are set to undefined
    if (this.options.stage === undefined) delete this.options.stage;
    if (this.options.region === undefined) delete this.options.region;

    const { [CUSTOM_OPTION]: customOptions } = this.service.custom || {};
    this.options = { ...defaultOptions, ...customOptions, ...this.options };

    // Prefix must start and end with '/'
    if (!this.options.prefix.startsWith('/')) {
      this.options.prefix = `/${this.options.prefix}`;
    }
    if (!this.options.prefix.endsWith('/')) this.options.prefix += '/';

    this.velocityContextOptions = {
      stage: this.options.stage,
      stageVariables: {}, // this.service.environment.stages[this.options.stage].vars,
    };

    // Parse CORS options
    this.options.corsAllowHeaders = this.options.corsAllowHeaders
      .replace(/\s/g, '')
      .split(',');
    this.options.corsAllowOrigin = this.options.corsAllowOrigin
      .replace(/\s/g, '')
      .split(',');
    this.options.corsExposedHeaders = this.options.corsExposedHeaders
      .replace(/\s/g, '')
      .split(',');

    if (this.options.corsDisallowCredentials) {
      this.options.corsAllowCredentials = false;
    }

    this.options.corsConfig = {
      credentials: this.options.corsAllowCredentials,
      exposedHeaders: this.options.corsExposedHeaders,
      headers: this.options.corsAllowHeaders,
      origin: this.options.corsAllowOrigin,
    };

    this.options.cacheInvalidationRegex = new RegExp(
      this.options.cacheInvalidationRegex,
    );

    this.serverlessLog(
      `Starting Offline: ${this.options.stage}/${this.options.region}.`,
    );
    debugLog('options:', this.options);
  }

  end() {
    this.serverlessLog('Halting offline server');
    functionHelper.cleanup();
    this.apiGateway.server
      .stop({ timeout: 5000 })
      .then(() => process.exit(this.exitCode));
  }

  _setupEvents() {
    this._verifySupportedRuntime();

    const defaultContentType = 'application/json';
    const { apiKeys } = this.service.provider;
    const protectedRoutes = [];

    // for simple API Key authentication model
    if (apiKeys) {
      this.serverlessLog(`Key with token: ${this.options.apiKey}`);

      if (this.options.noAuth) {
        this.serverlessLog(
          'Authorizers are turned off. You do not need to use x-api-key header.',
        );
      } else {
        this.serverlessLog('Remember to use x-api-key on the request headers');
      }
    }

    const serviceRuntime = this.service.provider.runtime;

    Object.keys(this.service.functions).forEach((key) => {
      const fun = this.service.getFunction(key);
      const funName = key;
      const servicePath = path.join(
        this.serverless.config.servicePath,
        this.options.location,
      );
      const funOptions = functionHelper.getFunctionOptions(
        fun,
        key,
        servicePath,
        serviceRuntime,
      );

      debugLog(`funOptions ${JSON.stringify(funOptions, null, 2)} `);
      this.printBlankLine();
      debugLog(funName, 'runtime', serviceRuntime);
      this.serverlessLog(`Routes for ${funName}:`);

      if (!fun.events) {
        fun.events = [];
      }

      // Add proxy for lamda invoke
      fun.events.push({
        http: {
          integration: 'lambda',
          method: 'POST',
          path: `{apiVersion}/functions/${fun.name}/invocations`,
          request: {
            template: {
              // AWS SDK for NodeJS specifies as 'binary/octet-stream' not 'application/json'
              'binary/octet-stream': '$input.body',
            },
          },
          response: {
            headers: {
              'Content-Type': 'application/json',
            },
          },
        },
      });

      // Adds a route for each http endpoint
      fun.events.forEach((event) => {
        if (event.websocket) {
          this.hasWebsocketRoutes = true;

          this._experimentalWebSocketSupportWarning();

          this.apiGatewayWebSocket._createWsAction(
            fun,
            funName,
            servicePath,
            funOptions,
            event,
          );

          return;
        }

        if (!event.http) return;

        this.apiGateway._createRoutes(
          event,
          funOptions,
          protectedRoutes,
          funName,
          servicePath,
          serviceRuntime,
          defaultContentType,
          key,
          fun,
        );
      });
    });
  }

  _verifySupportedRuntime() {
    let { runtime } = this.service.provider;

    if (runtime === 'provided') {
      if (this.options.providedRuntime) {
        runtime = this.options.providedRuntime;
      } else {
        throw new Error(
          'Runtime "provided" is unsupported. Please add a --providedRuntime CLI option.',
        );
      }
    }

    // print message but keep working (don't error out or exit process)
    if (!supportedRuntimes.has(runtime)) {
      this.printBlankLine();
      this.serverlessLog(`Warning: found unsupported runtime '${runtime}'`);
    }
  }

  // TODO: missing tests
  _verifyServerlessVersionCompatibility() {
    const { version: currentVersion } = this.serverless;
    const { serverless: requiredVersion } = peerDependencies;

    const versionIsSatisfied = satisfiesVersionRange(
      requiredVersion,
      currentVersion,
    );

    if (!versionIsSatisfied) {
      this.serverlessLog(
        `"Serverless-Offline" requires "Serverless" version ${requiredVersion} but found version ${currentVersion}.
         Be aware that functionality might be limited or has serious bugs.
         To avoid any issues update "Serverless" to a later version.
        `,
        'serverless-offline',
        { color: 'red' },
      );
    }
  }

  // TODO: eventually remove WARNING after release has been deemed stable
  _experimentalWebSocketSupportWarning() {
    // notify only once
    if (this._experimentalWarningNotified) {
      return;
    }

    this.serverlessLog(
      `WebSocket support in "Serverless-Offline is experimental.
       For any bugs, missing features or other feedback file an issue at https://github.com/dherault/serverless-offline/issues
      `,
      'serverless-offline',
      { color: 'magenta' },
    );

    this._experimentalWarningNotified = true;
  }
};
<commit_msg>Fix provided runtime<commit_after>'use strict';

const { exec } = require('child_process');
const path = require('path');
const ApiGateway = require('./ApiGateway');
const ApiGatewayWebSocket = require('./ApiGatewayWebSocket');
const debugLog = require('./debugLog');
const functionHelper = require('./functionHelper');
const { createDefaultApiKey, satisfiesVersionRange } = require('./utils');
const { CUSTOM_OPTION, supportedRuntimes } = require('./config/index.js');
const { peerDependencies } = require('../package.json');

module.exports = class ServerlessOffline {
  constructor(serverless, options) {
    this.serverless = serverless;
    this.service = serverless.service;
    this.serverlessLog = serverless.cli.log.bind(serverless.cli);
    this.options = options;
    this.exitCode = 0;
    this._experimentalWarningNotified = false;

    this.commands = {
      offline: {
        // add start nested options
        commands: {
          start: {
            lifecycleEvents: ['init', 'end'],
            usage:
              'Simulates API Gateway to call your lambda functions offline using backward compatible initialization.',
          },
        },
        lifecycleEvents: ['start'],
        options: {
          apiKey: {
            usage:
              'Defines the API key value to be used for endpoints marked as private. Defaults to a random hash.',
          },
          binPath: {
            shortcut: 'b',
            usage: 'Path to the Serverless binary.',
          },
          cacheInvalidationRegex: {
            usage:
              'Provide the plugin with a regexp to use for cache invalidation. Default: node_modules',
          },
          corsAllowHeaders: {
            usage:
              'Used to build the Access-Control-Allow-Headers header for CORS support.',
          },
          corsAllowOrigin: {
            usage:
              'Used to build the Access-Control-Allow-Origin header for CORS support.',
          },
          corsDisallowCredentials: {
            usage:
              'Used to override the Access-Control-Allow-Credentials default (which is true) to false.',
          },
          corsExposedHeaders: {
            usage:
              'USed to build the Access-Control-Exposed-Headers response header for CORS support',
          },
          disableCookieValidation: {
            usage: 'Used to disable cookie-validation on hapi.js-server',
          },
          enforceSecureCookies: {
            usage: 'Enforce secure cookies',
          },
          exec: {
            usage:
              'When provided, a shell script is executed when the server starts up, and the server will shut down after handling this command.',
          },
          hideStackTraces: {
            usage: 'Hide the stack trace on lambda failure. Default: false',
          },
          host: {
            shortcut: 'o',
            usage: 'The host name to listen on. Default: localhost',
          },
          httpsProtocol: {
            shortcut: 'H',
            usage:
              'To enable HTTPS, specify directory (relative to your cwd, typically your project dir) for both cert.pem and key.pem files.',
          },
          location: {
            shortcut: 'l',
            usage: "The root location of the handlers' files.",
          },
          noAuth: {
            usage: 'Turns off all authorizers',
          },
          noEnvironment: {
            usage:
              'Turns off loading of your environment variables from serverless.yml. Allows the usage of tools such as PM2 or docker-compose.',
          },
          noTimeout: {
            shortcut: 't',
            usage: 'Disables the timeout feature.',
          },
          port: {
            shortcut: 'P',
            usage: 'Port to listen on. Default: 3000',
          },
          prefix: {
            shortcut: 'p',
            usage:
              'Adds a prefix to every path, to send your requests to http://localhost:3000/prefix/[your_path] instead.',
          },
          preserveTrailingSlash: {
            usage: 'Used to keep trailing slashes on the request path',
          },
          printOutput: {
            usage: 'Outputs your lambda response to the terminal.',
          },
          providedRuntime: {
            usage: 'Sets the provided runtime for lambdas',
          },
          region: {
            shortcut: 'r',
            usage: 'The region used to populate your templates.',
          },
          resourceRoutes: {
            usage:
              'Turns on loading of your HTTP proxy settings from serverless.yml.',
          },
          showDuration: {
            usage: 'Show the execution time duration of the lambda function.',
          },
          skipCacheInvalidation: {
            shortcut: 'c',
            usage:
              'Tells the plugin to skip require cache invalidation. A script reloading tool like Nodemon might then be needed',
          },
          stage: {
            shortcut: 's',
            usage: 'The stage used to populate your templates.',
          },
          useSeparateProcesses: {
            usage: 'Uses separate node processes for handlers',
          },
          websocketPort: {
            usage: 'Websocket port to listen on. Default: 3001',
          },
        },
        usage: 'Simulates API Gateway to call your lambda functions offline.',
      },
    };

    this.hooks = {
      'offline:start:init': this.start.bind(this),
      'offline:start': this.startWithExplicitEnd.bind(this),
      'offline:start:end': this.end.bind(this),
    };
  }

  printBlankLine() {
    console.log();
  }

  logPluginIssue() {
    this.serverlessLog(
      'If you think this is an issue with the plugin please submit it, thanks!',
    );
    this.serverlessLog('https://github.com/dherault/serverless-offline/issues');
  }

  // Entry point for the plugin (sls offline) when running 'sls offline start'
  start() {
    this._verifyServerlessVersionCompatibility();

    // Some users would like to know their environment outside of the handler
    process.env.IS_OFFLINE = true;

    return Promise.resolve(this._buildServer())
      .then(() => this.apiGateway._listen())
      .then(() => this.hasWebsocketRoutes && this.apiGatewayWebSocket._listen())
      .then(() =>
        this.options.exec
          ? this._executeShellScript()
          : this._listenForTermination(),
      );
  }

  /**
   * Entry point for the plugin (sls offline) when running 'sls offline'
   * The call to this.end() would terminate the process before 'offline:start:end' could be consumed
   * by downstream plugins. When running sls offline that can be expected, but docs say that
   * 'sls offline start' will provide the init and end hooks for other plugins to consume
   * */
  startWithExplicitEnd() {
    return this.start().then(() => this.end());
  }

  _listenForTermination() {
    // SIGINT will be usually sent when user presses ctrl+c
    const waitForSigInt = new Promise((resolve) => {
      process.on('SIGINT', () => resolve('SIGINT'));
    });

    // SIGTERM is a default termination signal in many cases,
    // for example when "killing" a subprocess spawned in node
    // with child_process methods
    const waitForSigTerm = new Promise((resolve) => {
      process.on('SIGTERM', () => resolve('SIGTERM'));
    });

    return Promise.race([waitForSigInt, waitForSigTerm]).then((command) => {
      this.serverlessLog(`Got ${command} signal. Offline Halting...`);
    });
  }

  _executeShellScript() {
    const command = this.options.exec;
    const options = {
      env: {
        IS_OFFLINE: true,
        ...this.service.provider.environment,
        ...this.originalEnvironment,
      },
    };

    this.serverlessLog(`Offline executing script [${command}]`);

    return new Promise((resolve) => {
      exec(command, options, (error, stdout, stderr) => {
        this.serverlessLog(`exec stdout: [${stdout}]`);
        this.serverlessLog(`exec stderr: [${stderr}]`);

        if (error) {
          // Use the failed command's exit code, proceed as normal so that shutdown can occur gracefully
          this.serverlessLog(`Offline error executing script [${error}]`);
          this.exitCode = error.code || 1;
        }
        resolve();
      });
    });
  }

  _buildServer() {
    // Methods
    this._setOptions(); // Will create meaningful options from cli options
    this._storeOriginalEnvironment(); // stores the original process.env for assigning upon invoking the handlers

    this.apiGateway = new ApiGateway(
      this.serverless,
      this.options,
      this.velocityContextOptions,
    );

    const server = this.apiGateway._createServer();

    this.hasWebsocketRoutes = false;
    this.apiGatewayWebSocket = new ApiGatewayWebSocket(
      this.serverless,
      this.options,
    );
    this.apiGatewayWebSocket._createWebSocket();

    this._setupEvents();
    this.apiGateway._createResourceRoutes(); // HTTP Proxy defined in Resource
    this.apiGateway._create404Route(); // Not found handling

    return server;
  }

  _storeOriginalEnvironment() {
    this.originalEnvironment = { ...process.env };
  }

  _setOptions() {
    // Merge the different sources of values for this.options
    // Precedence is: command line options, YAML options, defaults.
    const defaultOptions = {
      apiKey: createDefaultApiKey(),
      cacheInvalidationRegex: 'node_modules',
      corsAllowOrigin: '*',
      corsAllowCredentials: true,
      corsAllowHeaders: 'accept,content-type,x-api-key,authorization',
      corsExposedHeaders: 'WWW-Authenticate,Server-Authorization',
      disableCookieValidation: false,
      enforceSecureCookies: false,
      exec: '',
      hideStackTraces: false,
      host: 'localhost',
      httpsProtocol: '',
      location: '.',
      noAuth: false,
      noEnvironment: false,
      noTimeout: false,
      port: 3000,
      prefix: '/',
      preserveTrailingSlash: false,
      printOutput: false,
      providedRuntime: '',
      showDuration: false,
      stage: this.service.provider.stage,
      region: this.service.provider.region,
      resourceRoutes: false,
      skipCacheInvalidation: false,
      useSeparateProcesses: false,
      websocketPort: 3001,
    };

    // In the constructor, stage and regions are set to undefined
    if (this.options.stage === undefined) delete this.options.stage;
    if (this.options.region === undefined) delete this.options.region;

    const { [CUSTOM_OPTION]: customOptions } = this.service.custom || {};
    this.options = { ...defaultOptions, ...customOptions, ...this.options };

    // Prefix must start and end with '/'
    if (!this.options.prefix.startsWith('/')) {
      this.options.prefix = `/${this.options.prefix}`;
    }
    if (!this.options.prefix.endsWith('/')) this.options.prefix += '/';

    this.velocityContextOptions = {
      stage: this.options.stage,
      stageVariables: {}, // this.service.environment.stages[this.options.stage].vars,
    };

    // Parse CORS options
    this.options.corsAllowHeaders = this.options.corsAllowHeaders
      .replace(/\s/g, '')
      .split(',');
    this.options.corsAllowOrigin = this.options.corsAllowOrigin
      .replace(/\s/g, '')
      .split(',');
    this.options.corsExposedHeaders = this.options.corsExposedHeaders
      .replace(/\s/g, '')
      .split(',');

    if (this.options.corsDisallowCredentials) {
      this.options.corsAllowCredentials = false;
    }

    this.options.corsConfig = {
      credentials: this.options.corsAllowCredentials,
      exposedHeaders: this.options.corsExposedHeaders,
      headers: this.options.corsAllowHeaders,
      origin: this.options.corsAllowOrigin,
    };

    this.options.cacheInvalidationRegex = new RegExp(
      this.options.cacheInvalidationRegex,
    );

    this.serverlessLog(
      `Starting Offline: ${this.options.stage}/${this.options.region}.`,
    );
    debugLog('options:', this.options);
  }

  end() {
    this.serverlessLog('Halting offline server');
    functionHelper.cleanup();
    this.apiGateway.server
      .stop({ timeout: 5000 })
      .then(() => process.exit(this.exitCode));
  }

  _setupEvents() {
    this._verifySupportedRuntime();

    const defaultContentType = 'application/json';
    const { apiKeys } = this.service.provider;
    const protectedRoutes = [];

    // for simple API Key authentication model
    if (apiKeys) {
      this.serverlessLog(`Key with token: ${this.options.apiKey}`);

      if (this.options.noAuth) {
        this.serverlessLog(
          'Authorizers are turned off. You do not need to use x-api-key header.',
        );
      } else {
        this.serverlessLog('Remember to use x-api-key on the request headers');
      }
    }

    let serviceRuntime = this.service.provider.runtime;

    if (serviceRuntime === 'provided') {
      serviceRuntime = this.options.providedRuntime;
    }

    Object.keys(this.service.functions).forEach((key) => {
      const fun = this.service.getFunction(key);
      const funName = key;
      const servicePath = path.join(
        this.serverless.config.servicePath,
        this.options.location,
      );
      const funOptions = functionHelper.getFunctionOptions(
        fun,
        key,
        servicePath,
        serviceRuntime,
      );

      debugLog(`funOptions ${JSON.stringify(funOptions, null, 2)} `);
      this.printBlankLine();
      debugLog(funName, 'runtime', serviceRuntime);
      this.serverlessLog(`Routes for ${funName}:`);

      if (!fun.events) {
        fun.events = [];
      }

      // Add proxy for lamda invoke
      fun.events.push({
        http: {
          integration: 'lambda',
          method: 'POST',
          path: `{apiVersion}/functions/${fun.name}/invocations`,
          request: {
            template: {
              // AWS SDK for NodeJS specifies as 'binary/octet-stream' not 'application/json'
              'binary/octet-stream': '$input.body',
            },
          },
          response: {
            headers: {
              'Content-Type': 'application/json',
            },
          },
        },
      });

      // Adds a route for each http endpoint
      fun.events.forEach((event) => {
        if (event.websocket) {
          this.hasWebsocketRoutes = true;

          this._experimentalWebSocketSupportWarning();

          this.apiGatewayWebSocket._createWsAction(
            fun,
            funName,
            servicePath,
            funOptions,
            event,
          );

          return;
        }

        if (!event.http) return;

        this.apiGateway._createRoutes(
          event,
          funOptions,
          protectedRoutes,
          funName,
          servicePath,
          serviceRuntime,
          defaultContentType,
          key,
          fun,
        );
      });
    });
  }

  _verifySupportedRuntime() {
    let { runtime } = this.service.provider;

    if (runtime === 'provided') {
      if (this.options.providedRuntime) {
        runtime = this.options.providedRuntime;
      } else {
        throw new Error(
          'Runtime "provided" is unsupported. Please add a --providedRuntime CLI option.',
        );
      }
    }

    // print message but keep working (don't error out or exit process)
    if (!supportedRuntimes.has(runtime)) {
      this.printBlankLine();
      this.serverlessLog(`Warning: found unsupported runtime '${runtime}'`);
    }
  }

  // TODO: missing tests
  _verifyServerlessVersionCompatibility() {
    const { version: currentVersion } = this.serverless;
    const { serverless: requiredVersion } = peerDependencies;

    const versionIsSatisfied = satisfiesVersionRange(
      requiredVersion,
      currentVersion,
    );

    if (!versionIsSatisfied) {
      this.serverlessLog(
        `"Serverless-Offline" requires "Serverless" version ${requiredVersion} but found version ${currentVersion}.
         Be aware that functionality might be limited or has serious bugs.
         To avoid any issues update "Serverless" to a later version.
        `,
        'serverless-offline',
        { color: 'red' },
      );
    }
  }

  // TODO: eventually remove WARNING after release has been deemed stable
  _experimentalWebSocketSupportWarning() {
    // notify only once
    if (this._experimentalWarningNotified) {
      return;
    }

    this.serverlessLog(
      `WebSocket support in "Serverless-Offline is experimental.
       For any bugs, missing features or other feedback file an issue at https://github.com/dherault/serverless-offline/issues
      `,
      'serverless-offline',
      { color: 'magenta' },
    );

    this._experimentalWarningNotified = true;
  }
};
<|endoftext|>


<commit_before>/**
 * Copyright 2018 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import {EventEmitter} from './EventEmitter.js';

export class SettingsComponent extends EventEmitter {
  constructor() {
    super();
    this.element = document.createElement('settings-component');
    this._contentElement = document.createElement('settings-content');
    this.element.appendChild(this._contentElement);

    this._selectedItem = null;
    document.body.addEventListener('keydown', event => {
      if (!this.element.parentElement)
        return;
      if (event.key === 'Escape') {
        this.hide();
        event.preventDefault();
        event.stopPropagation();
      }
    }, false);
    this._contentElement.addEventListener('click', event => {
      event.stopPropagation();
      event.preventDefault();
      // Allow selecting versions.
      if (!window.getSelection().isCollapsed)
        return;
      if (event.target.classList.contains('settings-close-icon')) {
        this.hide();
        return;
      }
      let item = event.target;
      while (item && item.tagName !== 'PRODUCT-VERSION')
        item = item.parentElement;
      if (!item)
        return;
      this._selectItem(item);
      const {product, versionName} = item[SettingsComponent._Symbol];
      this.hide();
      this.emit(SettingsComponent.Events.VersionSelected, product, versionName);
    }, false);
    this.element.addEventListener('click', () => this.hide(), false);
  }

  _selectItem(item) {
    if (this._selectedItem)
      this._selectedItem.classList.remove('selected');
    this._selectedItem = item;
    if (this._selectedItem)
      this._selectedItem.classList.add('selected');
  }

  show(product, version) {
    this._contentElement.innerHTML = '';
    const settingsHeader = document.createElement('settings-header');
    settingsHeader.innerHTML = `<h3>Settings</h3>`;
    const closeIcon = document.createElement('img');
    closeIcon.classList.add('settings-close-icon');
    closeIcon.src = './images/close.svg';
    settingsHeader.appendChild(closeIcon);
    this._contentElement.appendChild(settingsHeader);
    if (product) {
      const versionsContainer = document.createElement('product-versions');
      for (const description of product.versionDescriptions()) {
        const item = document.createElement('product-version');
        const name = document.createElement('version-name');
        name.textContent = description.name;
        item.appendChild(name);
        const subtitle = document.createElement('version-description');
        subtitle.textContent = description.description;
        item.appendChild(subtitle);
        const date = document.createElement('version-date');
        date.textContent = formatDate(description.date);
        item.appendChild(date);
        item[SettingsComponent._Symbol] = {product, versionName: description.name};
        versionsContainer.appendChild(item);
        if (description.name === version.name())
          this._selectItem(item);
      }
      this._contentElement.appendChild(versionsContainer);
      this._contentElement.appendChild(product.settingsFooterElement());
    }
    const websiteVersionText = window.__WEBSITE_VERSION__ || 'tip-of-tree';
    const websiteVersion = document.createElement('website-version');
    websiteVersion.innerHTML = `<div>WebSite Version: <code>${websiteVersionText}</code> <a href="https://github.com/GoogleChromeLabs/pptr.dev/issues">File a bug!</a></div>`;
    this._contentElement.appendChild(websiteVersion);
    document.body.appendChild(this.element);
    if (this._selectedItem)
      this._selectedItem.scrollIntoViewIfNeeded();

    function formatDate(date) {
      if (!date)
        return 'N/A';
      const monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
      const day = date.getDate();
      const month = date.getMonth();
      const year = date.getFullYear();
      return monthNames[month] + ' ' + day + ', ' + year;
    }
  }

  hide() {
    this.element.remove();
    // Cleanup content to free some memory.
    this._contentElement.innerHTML = '';
    this._selectedItem = null;
  }
}

SettingsComponent._Symbol = Symbol('SettingsComponent._Symbol');

SettingsComponent.Events = {
  VersionSelected: 'VersionSelected',
};
<commit_msg>fix(settings): "file a bug" link should be clickable.<commit_after>/**
 * Copyright 2018 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import {EventEmitter} from './EventEmitter.js';

export class SettingsComponent extends EventEmitter {
  constructor() {
    super();
    this.element = document.createElement('settings-component');
    this._contentElement = document.createElement('settings-content');
    this.element.appendChild(this._contentElement);

    this._selectedItem = null;
    document.body.addEventListener('keydown', event => {
      if (!this.element.parentElement)
        return;
      if (event.key === 'Escape') {
        this.hide();
        event.preventDefault();
        event.stopPropagation();
      }
    }, false);
    this._contentElement.addEventListener('click', event => {
      // Support clicks on links, e.g. "file a bug".
      if (event.target.tagName === 'A') {
        event.stopPropagation();
        return;
      }
      event.preventDefault();
      // Allow selecting versions.
      if (!window.getSelection().isCollapsed)
        return;
      if (event.target.classList.contains('settings-close-icon')) {
        this.hide();
        return;
      }
      let item = event.target;
      while (item && item.tagName !== 'PRODUCT-VERSION')
        item = item.parentElement;
      if (!item)
        return;
      this._selectItem(item);
      const {product, versionName} = item[SettingsComponent._Symbol];
      this.hide();
      this.emit(SettingsComponent.Events.VersionSelected, product, versionName);
    }, false);
    this.element.addEventListener('click', () => this.hide(), false);
  }

  _selectItem(item) {
    if (this._selectedItem)
      this._selectedItem.classList.remove('selected');
    this._selectedItem = item;
    if (this._selectedItem)
      this._selectedItem.classList.add('selected');
  }

  show(product, version) {
    this._contentElement.innerHTML = '';
    const settingsHeader = document.createElement('settings-header');
    settingsHeader.innerHTML = `<h3>Settings</h3>`;
    const closeIcon = document.createElement('img');
    closeIcon.classList.add('settings-close-icon');
    closeIcon.src = './images/close.svg';
    settingsHeader.appendChild(closeIcon);
    this._contentElement.appendChild(settingsHeader);
    if (product) {
      const versionsContainer = document.createElement('product-versions');
      for (const description of product.versionDescriptions()) {
        const item = document.createElement('product-version');
        const name = document.createElement('version-name');
        name.textContent = description.name;
        item.appendChild(name);
        const subtitle = document.createElement('version-description');
        subtitle.textContent = description.description;
        item.appendChild(subtitle);
        const date = document.createElement('version-date');
        date.textContent = formatDate(description.date);
        item.appendChild(date);
        item[SettingsComponent._Symbol] = {product, versionName: description.name};
        versionsContainer.appendChild(item);
        if (description.name === version.name())
          this._selectItem(item);
      }
      this._contentElement.appendChild(versionsContainer);
      this._contentElement.appendChild(product.settingsFooterElement());
    }
    const websiteVersionText = window.__WEBSITE_VERSION__ || 'tip-of-tree';
    const websiteVersion = document.createElement('website-version');
    websiteVersion.innerHTML = `<div>WebSite Version: <code>${websiteVersionText}</code> <a href="https://github.com/GoogleChromeLabs/pptr.dev/issues">File a bug!</a></div>`;
    this._contentElement.appendChild(websiteVersion);
    document.body.appendChild(this.element);
    if (this._selectedItem)
      this._selectedItem.scrollIntoViewIfNeeded();

    function formatDate(date) {
      if (!date)
        return 'N/A';
      const monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
      const day = date.getDate();
      const month = date.getMonth();
      const year = date.getFullYear();
      return monthNames[month] + ' ' + day + ', ' + year;
    }
  }

  hide() {
    this.element.remove();
    // Cleanup content to free some memory.
    this._contentElement.innerHTML = '';
    this._selectedItem = null;
  }
}

SettingsComponent._Symbol = Symbol('SettingsComponent._Symbol');

SettingsComponent.Events = {
  VersionSelected: 'VersionSelected',
};
<|endoftext|>


<commit_before>import React from 'react';
import Portal from 'react-portal';
import { boxShadow } from 'olymp-fela';
import { Menu as AntMenu } from 'antd';
import { createComponent } from 'olymp-fela';

export const Menu = createComponent(({ theme }) => ({
  position: 'fixed',
  top: 0,
  zIndex: 10,
  left: '50%',
  transform: 'translateX(-50%)',
  // background: theme.light1,
  background: theme.dark,
  borderBottom: 0,
  // boxShadow: boxShadow(theme.dark3),
  borderTop: 0,
  '> li': {
    padding: 0,
    // color: `${theme.dark1}!important`,
    color: `${theme.light}!important`,
    '> .ant-menu-submenu-title': {
      padding: 0,
    },
  },
  '> li:hover': {
    // color: theme.light1,
    color: theme.dark,
  },
}), AntMenu, p => Object.keys(p));

export const Button = createComponent(() => ({
  paddingX: 20,
}), ({ className, onMouseDown, children, innerKey, ...props }) => (

    {children}

), p => Object.keys(p));

export default createComponent(({ theme }) => ({
  /*width: '100%',
  display: 'flex',
  justifyContent: 'center',*/
}), (props) => {
  const { isOpened, className, children } = props;
  return (
    <Portal isOpened={!!isOpened}>
      <Menu mode="horizontal">
        {children}
      </Menu>
    </Portal>
  );
}, p => Object.keys(p));
<commit_msg>shadow<commit_after>import React from 'react';
import Portal from 'react-portal';
import { boxShadow } from 'olymp-fela';
import { Menu as AntMenu } from 'antd';
import { createComponent } from 'olymp-fela';

export const Menu = createComponent(({ theme }) => ({
  position: 'fixed',
  top: 0,
  zIndex: 10,
  left: '50%',
  transform: 'translateX(-50%)',
  // background: theme.light1,
  background: theme.dark,
  borderBottom: 0,
  boxShadow: boxShadow(theme.dark3),
  borderTop: 0,
  '> li': {
    padding: 0,
    // color: `${theme.dark1}!important`,
    color: `${theme.light}!important`,
    '> .ant-menu-submenu-title': {
      padding: 0,
    },
  },
  '> li:hover': {
    // color: theme.light1,
    color: theme.dark,
  },
}), AntMenu, p => Object.keys(p));

export const Button = createComponent(() => ({
  paddingX: 20,
}), ({ className, onMouseDown, children, innerKey, ...props }) => (

    {children}

), p => Object.keys(p));

export default createComponent(({ theme }) => ({
  /*width: '100%',
  display: 'flex',
  justifyContent: 'center',*/
}), (props) => {
  const { isOpened, className, children } = props;
  return (
    <Portal isOpened={!!isOpened}>
      <Menu mode="horizontal">
        {children}
      </Menu>
    </Portal>
  );
}, p => Object.keys(p));
<|endoftext|>


<commit_before>const first = require('.')
const t = require('ava')

t(t => {
  //let result = first(nums())
  //t.is(result, 1)
  t.is(first([4, 5]), 4)
})
<commit_msg>first: fixed test<commit_after>const first = require('.')
const t = require('ava')

t(t => {
  let result = first((function* nums() {
    yield 1
    t.fail()
    yield 2
  })())
  t.is(result, 1)
  t.is(first([4, 5]), 4)
})
<|endoftext|>


<commit_before>
// https://www.npmjs.com/package/node-sass

module.exports = {

  /**
   * outputFilename: The filename of the saved CSS file
   * from the sass build. The directory which it is saved in
   * is set within the "buildDir" config options.
   */
  outputFilename: 'main.css',

  /**
   * sourceMap: If source map should be built or not.
   */
  sourceMap: false,

  /**
   * outputStyle: How node-sass should output the css file.
   */
  outputStyle: 'expanded',

  /**
   * autoprefixer: The config options for autoprefixer.
   * Excluding this config will skip applying autoprefixer.
   * https://www.npmjs.com/package/autoprefixer
   */
  autoprefixer: {
    browsers: [
      'last 2 versions',
      'iOS >= 8',
      'Android >= 4.4',
      'Explorer >= 11',
      'ExplorerMobile >= 11'
    ],
    cascade: false
  },

  /**
   * includePaths: Used by node-sass for additional
   * paths to search for sass imports by just name.
   */
  includePaths: [
    'node_modules/ionic-angular/themes',
    'node_modules/ionicons/dist/scss'
  ],

  /**
   * includeFiles: An array of regex patterns to search for
   * sass files in the same directory as the component module.
   * If a file matches both include and exclude patterns, then
   * the file will be excluded.
   */
  includeFiles: [
    /\.(scss)$/i
  ],

  /**
   * excludeFiles: An array of regex patterns for files which
   * should be excluded. If a file matches both include and exclude
   * patterns, then the file will be excluded.
   */
  excludeFiles: [
    /*  /\.(wp).(scss)$/i  */
  ],

  /**
   * variableSassFiles: Lists out the files which include
   * only sass variables. These variables are the first sass files
   * to be imported so their values override default variables.
   */
  variableSassFiles: [
    '{{SRC}}/theme/variables.scss'
  ],

  /**
   * directoryMaps: Compiled JS modules may be within a different
   * directory than its source file and sibling component sass files.
   * For example, NGC places it's files within the .tmp directory
   * but doesn't copy over its sass files. This is useful so sass
   * also checks the JavaScript's source directory for sass files.
   */
  directoryMaps: {
    '{{TMP}}': '{{SRC}}'
  },

  /**
   * excludeModules: Used just as a way to skip over
   * modules which we know wouldn't have any sass to be
   * bundled. "excludeModules" isn't necessary, but is a
   * good way to speed up build times by skipping modules.
   */
  excludeModules: [
    '@angular',
    '@ionic/storage',
    'commonjs-proxy',
    'core-js',
    'ionic-native',
    'rxjs',
    'rxjs-es',
    'zone.js'
  ]

};
<commit_msg>Remove @ionic/storage from sass config<commit_after>
// https://www.npmjs.com/package/node-sass

module.exports = {

  /**
   * outputFilename: The filename of the saved CSS file
   * from the sass build. The directory which it is saved in
   * is set within the "buildDir" config options.
   */
  outputFilename: 'main.css',

  /**
   * sourceMap: If source map should be built or not.
   */
  sourceMap: false,

  /**
   * outputStyle: How node-sass should output the css file.
   */
  outputStyle: 'expanded',

  /**
   * autoprefixer: The config options for autoprefixer.
   * Excluding this config will skip applying autoprefixer.
   * https://www.npmjs.com/package/autoprefixer
   */
  autoprefixer: {
    browsers: [
      'last 2 versions',
      'iOS >= 8',
      'Android >= 4.4',
      'Explorer >= 11',
      'ExplorerMobile >= 11'
    ],
    cascade: false
  },

  /**
   * includePaths: Used by node-sass for additional
   * paths to search for sass imports by just name.
   */
  includePaths: [
    'node_modules/ionic-angular/themes',
    'node_modules/ionicons/dist/scss'
  ],

  /**
   * includeFiles: An array of regex patterns to search for
   * sass files in the same directory as the component module.
   * If a file matches both include and exclude patterns, then
   * the file will be excluded.
   */
  includeFiles: [
    /\.(scss)$/i
  ],

  /**
   * excludeFiles: An array of regex patterns for files which
   * should be excluded. If a file matches both include and exclude
   * patterns, then the file will be excluded.
   */
  excludeFiles: [
    /*  /\.(wp).(scss)$/i  */
  ],

  /**
   * variableSassFiles: Lists out the files which include
   * only sass variables. These variables are the first sass files
   * to be imported so their values override default variables.
   */
  variableSassFiles: [
    '{{SRC}}/theme/variables.scss'
  ],

  /**
   * directoryMaps: Compiled JS modules may be within a different
   * directory than its source file and sibling component sass files.
   * For example, NGC places it's files within the .tmp directory
   * but doesn't copy over its sass files. This is useful so sass
   * also checks the JavaScript's source directory for sass files.
   */
  directoryMaps: {
    '{{TMP}}': '{{SRC}}'
  },

  /**
   * excludeModules: Used just as a way to skip over
   * modules which we know wouldn't have any sass to be
   * bundled. "excludeModules" isn't necessary, but is a
   * good way to speed up build times by skipping modules.
   */
  excludeModules: [
    '@angular',
    'commonjs-proxy',
    'core-js',
    'ionic-native',
    'rxjs',
    'rxjs-es',
    'zone.js'
  ]

};
<|endoftext|>


<commit_before>var config = require('../../package.json');
var settings = config.settings;

exports.default = {
  servers: {
    web: function(api){
      return {
        enabled: true,
        // HTTP or HTTPS?
        secure: false,
        // Passed to https.createServer if secure=true. Should contain SSL certificates
        serverOptions: {},
        // Port or Socket Path
        port: process.env.PORT || settings.developmentport,
        // Which IP to listen on (use '0.0.0.0' for all; '::' for all on ipv4 and ipv6)
        // Set to `null` when listening to socket
        bindIP: '0.0.0.0',
        // Any additional headers you want actionhero to respond with
        httpHeaders : {
          'X-Powered-By'                : api.config.general.serverName,
          'Access-Control-Allow-Origin' : '*',
          'Access-Control-Allow-Methods': 'HEAD, GET, POST, PUT, PATCH, DELETE, OPTIONS, TRACE',
          'Access-Control-Allow-Headers': 'Content-Type',
        },
        // Route that actions will be served from; secondary route against this route will be treated as actions,
        //  IE: /api/?action=test == /api/test/
        urlPathForActions : 'api',
        // Route that static files will be served from;
        //  path (relative to your project root) to serve static content from
        //  set to `null` to disable the file server entirely
        urlPathForFiles : 'public',
        // When visiting the root URL, should visitors see 'api' or 'file'?
        //  Visitors can always visit /api and /public as normal
        rootEndpointType : 'file',
        // simple routing also adds an 'all' route which matches /api/:action for all actions
        simpleRouting : true,
        // queryRouting allows an action to be defined via a URL param, ie: /api?action=:action
        queryRouting : true,
        // The header which will be returned for all flat file served from /public; defined in seconds
        flatFileCacheDuration : 60,
        // How many times should we try to boot the srever?
        // This might happen if the port is in use by another process or the socketfile is claimed
        bootAttempts: 1,
        // Settings for determining the id of an http(s) request (browser-fingerprint)
        fingerprintOptions : {
          cookieKey: 'sessionID',
          toSetCookie: true,
          onlyStaticElements: false,
          settings: {
            path: '/',
            expires: 3600000,
          }
        },
        // Options to be applied to incoming file uploads.
        //  More options and details at https://github.com/felixge/node-formidable
        formOptions: {
          uploadDir: '/tmp',
          keepExtensions: false,
          maxFieldsSize: 1024 * 1024 * 100
        },
        // Should we pad JSON responses with whitespace to make them more human-readable?
        // set to null to disable
        padding: 2,
        // Options to configure metadata in responses
        metadataOptions: {
          serverInformation: true,
          requesterInformation: true
        },
        // When true, returnErrorCodes will modify the response header for http(s) clients if connection.error is not null.
        //  You can also set connection.rawConnection.responseHttpCode to specify a code per request.
        returnErrorCodes: true
      }
    }
  },
  database: {
    host: 'https://flasklocations.smileupps.com/'
  }
}

exports.production = {
  servers: {
    web: function(api){
      return {
        // Port or Socket Path
        port: process.env.PORT || settings.productionport,
        padding: null,
        metadataOptions: {
          serverInformation: false,
          requesterInformation: false
        }
      }
    }
  }
}

exports.test = {
  servers: {
    web: function(api){
      return {
        secure: false,
        port: 18080,
        matchExtensionMime: true,
        metadataOptions: {
          serverInformation: true,
          requesterInformation: true
        }
      }
    }
  }
}<commit_msg>Provide seperate env var for dev<commit_after>var config = require('../../package.json');
var settings = config.settings;

exports.default = {
  servers: {
    web: function(api){
      return {
        enabled: true,
        // HTTP or HTTPS?
        secure: false,
        // Passed to https.createServer if secure=true. Should contain SSL certificates
        serverOptions: {},
        // Port or Socket Path
        port: process.env.DEV_PORT || settings.developmentport,
        // Which IP to listen on (use '0.0.0.0' for all; '::' for all on ipv4 and ipv6)
        // Set to `null` when listening to socket
        bindIP: '0.0.0.0',
        // Any additional headers you want actionhero to respond with
        httpHeaders : {
          'X-Powered-By'                : api.config.general.serverName,
          'Access-Control-Allow-Origin' : '*',
          'Access-Control-Allow-Methods': 'HEAD, GET, POST, PUT, PATCH, DELETE, OPTIONS, TRACE',
          'Access-Control-Allow-Headers': 'Content-Type',
        },
        // Route that actions will be served from; secondary route against this route will be treated as actions,
        //  IE: /api/?action=test == /api/test/
        urlPathForActions : 'api',
        // Route that static files will be served from;
        //  path (relative to your project root) to serve static content from
        //  set to `null` to disable the file server entirely
        urlPathForFiles : 'public',
        // When visiting the root URL, should visitors see 'api' or 'file'?
        //  Visitors can always visit /api and /public as normal
        rootEndpointType : 'file',
        // simple routing also adds an 'all' route which matches /api/:action for all actions
        simpleRouting : true,
        // queryRouting allows an action to be defined via a URL param, ie: /api?action=:action
        queryRouting : true,
        // The header which will be returned for all flat file served from /public; defined in seconds
        flatFileCacheDuration : 60,
        // How many times should we try to boot the srever?
        // This might happen if the port is in use by another process or the socketfile is claimed
        bootAttempts: 1,
        // Settings for determining the id of an http(s) request (browser-fingerprint)
        fingerprintOptions : {
          cookieKey: 'sessionID',
          toSetCookie: true,
          onlyStaticElements: false,
          settings: {
            path: '/',
            expires: 3600000,
          }
        },
        // Options to be applied to incoming file uploads.
        //  More options and details at https://github.com/felixge/node-formidable
        formOptions: {
          uploadDir: '/tmp',
          keepExtensions: false,
          maxFieldsSize: 1024 * 1024 * 100
        },
        // Should we pad JSON responses with whitespace to make them more human-readable?
        // set to null to disable
        padding: 2,
        // Options to configure metadata in responses
        metadataOptions: {
          serverInformation: true,
          requesterInformation: true
        },
        // When true, returnErrorCodes will modify the response header for http(s) clients if connection.error is not null.
        //  You can also set connection.rawConnection.responseHttpCode to specify a code per request.
        returnErrorCodes: true
      }
    }
  },
  database: {
    host: 'https://flasklocations.smileupps.com/'
  }
}

exports.production = {
  servers: {
    web: function(api){
      return {
        // Port or Socket Path
        port: process.env.PORT || settings.productionport,
        padding: null,
        metadataOptions: {
          serverInformation: false,
          requesterInformation: false
        }
      }
    }
  }
}

exports.test = {
  servers: {
    web: function(api){
      return {
        secure: false,
        port: 18080,
        matchExtensionMime: true,
        metadataOptions: {
          serverInformation: true,
          requesterInformation: true
        }
      }
    }
  }
}<|endoftext|>


<commit_before>/**
 * @fileOverview Multiple Modules build operations.
 */

var __     = require('lodash');
var async = require('async');

var helpers= require('./helpers');
var mantriCompile = require('./mantri-build-compile');

var buildModule = module.exports = {};

/**
 * Checks if there are modules defined and builds them.
 *
 * @param {Object} buildOpts Build options.
 * @param {Object} options The options object.
 * @param {Function(Error=)} cb Callback
 */
buildModule.buildModules = function(buildOpts, options, cb) {

  if (!__.isObject(buildOpts.buildModules)) {
    return cb();
  }

  var namespaces = __.keys(buildOpts.buildModules);

  async.map(
    namespaces,
    __.partial(buildModule._compileModule, buildOpts, options),
    cb
  );

};

/**
 * Prepare and compile a module. Used when multiple modules are defined in
 * mantriConf.json file.
 *
 * @param {Object} buildOpts Build options.
 * @param {Object} options The options object.
 * @param {Object} namespace the Module's namespace.
 * @param {Function(Error=)} cb Callback.
 * @private
 */
buildModule._compileModule = function(buildOpts, options, namespace, cb) {
  // The module in the "buildModule" key defined in the mantriConf.json file.
  var moduleConf = buildOpts.buildModules[namespace];

  var compileOpts = {
    jsRoot: buildOpts.jsRoot,
    gmockDir: options._tmpDir,
    dest: moduleConf.dest,
    target: buildOpts.target,
    debug: options.debug,
    namespace: namespace,
    outputWrapper: buildModule._checkModuleOutputWrapper(namespace, moduleConf),
  };

  helpers.log.debug( compileOpts.debug, 'Compiling module: ' + namespace);

  mantriCompile.compile(compileOpts, function(status) {
    if (!status) {return cb(new Error());}
    cb();
  });
};

/**
 * Check the outputWrapper option and if not defined return custom dirty
 * solution to modules so they properly export their payload.
 *
 * @param {Object} namespace the Module's namespace.
 * @param {Object} moduleConf  The module in the "buildModule" key defined in the mantriConf.json file.
 * @return {string|undefined} The proper outputWrapper to apply.
 * @private
 */
buildModule._checkModuleOutputWrapper = function(namespace, moduleConf) {

  // don't apply custom wrapper if explicitly set to 'null'
  if (moduleConf.outputWrapper === null) {return;}

  if (__.isString(moduleConf.outputWrapper) && moduleConf.outputWrapper.length) {
    // user defined wrapper
    return moduleConf.outputWrapper;
  }

  return buildModule._getModuleOutputWrapper(namespace);
};

/**
 * Generate and return a custom output wrapper for the specific module.
 *
 * For a namespace of 'app.ctrl.dong' the following string would be returned
 * (without the newlines or spaces):
 *    this.app = app || {};
 *    this.app.ctrl = app.ctrl || {};
 *    this.app.ctrl.dong = app.ctrl.dong;
 *
 * @return {string} the proper js text that exports the module.
 * @private
 */
buildModule._getModuleOutputWrapper = function(namespace) {
  var nsParts = namespace.split('.');
  var totalParts = nsParts.length;
  var exportString = '';
  var tempString = '';
  var orAssign = '||{};';
  var exportTarget = 'this';

  nsParts.forEach(function(part, index) {
    if (index === 0) {
      tempString = part;
      exportString = exportTarget+ '.' + tempString + '=' + tempString + orAssign;
    } else {
      tempString += '.' + part;
      if ((index + 1) === totalParts) {
        // last part
        exportString += exportTarget+ '.' + tempString + '=' + tempString + ';';
      } else {
        exportString += exportTarget+ '.' + tempString + '=' + tempString + orAssign;
      }
    }
  });

  return exportString;
};<commit_msg>work on mult module wrapper<commit_after>/**
 * @fileOverview Multiple Modules build operations.
 */

var __     = require('lodash');
var async = require('async');

var helpers= require('./helpers');
var mantriCompile = require('./mantri-build-compile');

var buildModule = module.exports = {};

/**
 * Checks if there are modules defined and builds them.
 *
 * @param {Object} buildOpts Build options.
 * @param {Object} options The options object.
 * @param {Function(Error=)} cb Callback
 */
buildModule.buildModules = function(buildOpts, options, cb) {

  if (!__.isObject(buildOpts.buildModules)) {
    return cb();
  }

  var namespaces = __.keys(buildOpts.buildModules);

  async.map(
    namespaces,
    __.partial(buildModule._compileModule, buildOpts, options),
    cb
  );

};

/**
 * Prepare and compile a module. Used when multiple modules are defined in
 * mantriConf.json file.
 *
 * @param {Object} buildOpts Build options.
 * @param {Object} options The options object.
 * @param {Object} namespace the Module's namespace.
 * @param {Function(Error=)} cb Callback.
 * @private
 */
buildModule._compileModule = function(buildOpts, options, namespace, cb) {
  // The module in the "buildModule" key defined in the mantriConf.json file.
  var moduleConf = buildOpts.buildModules[namespace];

  var compileOpts = {
    jsRoot: buildOpts.jsRoot,
    gmockDir: options._tmpDir,
    dest: moduleConf.dest,
    target: buildOpts.target,
    debug: options.debug,
    namespace: namespace,
    outputWrapper: buildModule._checkModuleOutputWrapper(namespace, moduleConf),
  };

  helpers.log.debug( compileOpts.debug, 'Compiling module: ' + namespace);

  mantriCompile.compile(compileOpts, function(status) {
    if (!status) {return cb(new Error());}
    cb();
  });
};

/**
 * Check the outputWrapper option and if not defined return custom dirty
 * solution to modules so they properly export their payload.
 *
 * @param {Object} namespace the Module's namespace.
 * @param {Object} moduleConf  The module in the "buildModule" key defined in the mantriConf.json file.
 * @return {string|undefined} The proper outputWrapper to apply.
 * @private
 */
buildModule._checkModuleOutputWrapper = function(namespace, moduleConf) {

  // don't apply custom wrapper if explicitly set to 'null'
  if (moduleConf.outputWrapper === null) {return;}

  if (__.isString(moduleConf.outputWrapper) && moduleConf.outputWrapper.length) {
    // user defined wrapper
    return moduleConf.outputWrapper;
  }

  // apply the custom wrapper
  var exportString = buildModule._getWrapperExportString(namespace);

  var wrapper = '(function(){%output%;' + exportString +'}).call(this);';

  return wrapper;
};

/**
 * Generate and return a custom export string for the specific module.
 *
 * For a namespace of 'app.ctrl.dong' the following string would be returned
 * (without the newlines or spaces):
 *    this.app = app || {};
 *    this.app.ctrl = app.ctrl || {};
 *    this.app.ctrl.dong = app.ctrl.dong;
 *
 * @return {string} the proper js text that exports the module.
 * @private
 */
buildModule._getWrapperExportString = function(namespace) {
  var nsParts = namespace.split('.');
  var totalParts = nsParts.length;
  var exportString = '';
  var tempString = '';
  var orAssign = '||{};';
  var exportTarget = 'this';

  nsParts.forEach(function(part, index) {
    if (index === 0) {
      tempString = part;
      exportString = exportTarget+ '.' + tempString + '=' + tempString + orAssign;
    } else {
      tempString += '.' + part;
      if ((index + 1) === totalParts) {
        // last part
        exportString += exportTarget+ '.' + tempString + '=' + tempString + ';';
      } else {
        exportString += exportTarget+ '.' + tempString + '=' + tempString + orAssign;
      }
    }
  });

  return exportString;
};
<|endoftext|>


<commit_before>"use strict";

const webpack = require("webpack");

const webpackMerge = require("webpack-merge"); // Used to merge webpack configs
const commonConfig = require("./webpack.common.js"); // common configuration between environments

// Helpers
const helpers = require("./helpers");

// Webpack Plugins
const ExtractTextWebpackPlugin = require("extract-text-webpack-plugin");

// Metadata
const METADATA = webpackMerge(commonConfig.metadata, {
    HOST: process.env.HOST || "localhost",
    PORT: process.env.PORT || 3000,
    ENV: process.env.ENV = process.env.NODE_ENV = "development",
    HMR: helpers.hasProcessFlag("hot"),
    PRODUCTION: false,
    DEVELOPMENT: true,
});

// Directives to be used in CSP header
// References
// https://developer.mozilla.org/en-US/docs/Web/Security/CSP
// https://scotthelme.co.uk/csp-cheat-sheet
const cspDirectives = [
    "base-uri 'self'",
    "default-src 'self'",
    "child-src 'self'",
    "connect-src 'self' http://my.awesome.api ws://localhost:3000",  // http://my.awesome.api is due to the mock REST api mock baseUrl and ws://localhost:3000" is due to FakeRest
    "font-src 'self'",
    "form-action 'self'",
    "frame-src 'self'",   // TODO: deprecated. Use child-src instead. Used here because child-src is not yet supported by Firefox. Remove as soon as it is fully supported
    "frame-ancestors 'none'",  // the app will not be allowed to be embedded in an iframe (roughly equivalent to X-Frame-Options: DENY)
    "img-src 'self' data: image/png",  // data: image/png" is due to Angular Material loading PNG images in base64 encoding
    "media-src 'self'",
    "object-src 'self'",
    "plugin-types application/pdf",  // valid mime-types for plugins invoked via <object> and <embed>  // TODO: not yet supported by Firefox
    "script-src 'self' 'unsafe-eval'",  // 'unsafe-eval' is due to Angular Material inline theming (see issue https://github.com/angular/material/issues/980)
    "style-src 'self' 'unsafe-inline'",  // 'unsafe-inline' is due to Angular Material inline theming (see issue https://github.com/angular/material/issues/980)
    "referrer no-referrer",
    "reflected-xss block",
    "block-all-mixed-content",
    //"upgrade-insecure-requests", // see https://github.com/dsebastien/angularjs-webpack-starter/issues/113
    "report-uri http://localhost"  // TODO: define an specific URL to POST the reports of policy failures
];

/*
 * Config
 * IMPORTANT: notice that the configuration below is MERGED with the common configuration (commonConfig)
 * reference: http://webpack.github.io/docs/configuration.html#cli
 */
module.exports = webpackMerge(commonConfig, {
    // static data for index.html
    metadata: METADATA,

    // Developer tool to enhance debugging
    // reference: https://webpack.github.io/docs/configuration.html#devtool
    // reference: https://github.com/webpack/docs/wiki/build-performance#sourcemaps
    devtool: "source-map",

    // Cache generated modules and chunks to improve performance for multiple incremental builds.
    // Enabled by default in watch mode.
    // You can pass false to disable it
    // reference: http://webpack.github.io/docs/configuration.html#cache
    //cache: true,

    // Switch loaders to debug mode
    // reference: http://webpack.github.io/docs/configuration.html#debug
    debug: true,

    // the entry point for the bundles
    // reference: http://webpack.github.io/docs/configuration.html#entry
    entry: {
        "polyfills": helpers.root("src/polyfills.ts"),
        "vendor-styles": helpers.root("src/vendor-styles.ts"),
        "main-styles": helpers.root("src/main-styles.ts"), // our angular app's styles. Useful only changing the styles bundle while working on styling
        "vendor": helpers.root("src/vendor.ts"),
        "main": helpers.root("src/main.ts"), // our angular app
    },

    // Options affecting the normal modules.
    // reference: http://webpack.github.io/docs/configuration.html#module
    module: {
        // An array of automatically applied loaders.
        //
        // IMPORTANT: The loaders here are resolved relative to the resource which they are applied to.
        // This means they are not resolved relative to the configuration file.
        //
        // reference: http://webpack.github.io/docs/configuration.html#module-loaders
        loaders: [
            // Support for .ts files.
            // reference: https://github.com/s-panferov/awesome-typescript-loader
            {
                test: /\.ts$/,
                loader: "awesome-typescript",
                exclude: [
                    /\.e2e\.ts$/, // exclude end-to-end tests
                    /\.spec\.ts$/, // exclude unit tests
                ],
            },
        ],
    },

    // Add additional plugins to the compiler.
    // reference: http://webpack.github.io/docs/configuration.html#plugins
    plugins: [
        // Environment helpers (when adding more properties make sure you include them in environment.d.ts)
        // Plugin: DefinePlugin
        // Description: Define free variables.
        // Useful for having development builds with debug logging or adding global constants.
        // reference: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
        // NOTE: when adding more properties make sure you include them in custom-typings.d.ts
        new webpack.DefinePlugin({
            "ENV": JSON.stringify(METADATA.ENV),
            "NODE_ENV": JSON.stringify(METADATA.ENV),
            "HMR": METADATA.HMR,
            "PRODUCTION": METADATA.PRODUCTION,
            "DEVELOPMENT": METADATA.DEVELOPMENT,
            "process.env": {
                "ENV": JSON.stringify(METADATA.ENV),
                "NODE_ENV": JSON.stringify(METADATA.ENV),
                "HMR": METADATA.HMR,
                "PRODUCTION": METADATA.PRODUCTION,
                "DEVELOPMENT": METADATA.DEVELOPMENT,
            },
        }),

        // Plugin: CommonsChunkPlugin
        // Description: Shares common code between the pages.
        // It identifies common modules and put them into a commons chunk.
        // reference: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
        // reference: https://github.com/webpack/docs/wiki/optimization#multi-page-app
        new webpack.optimize.CommonsChunkPlugin({
            name: helpers.reverse([
                "polyfills",
                "vendor",
                "main",
                "vendor-styles",
                "main-styles"
            ]),
        }),

        // Plugin: ExtractTextWebpackPlugin
        // Description: Extract css file contents
        // reference: https://github.com/webpack/extract-text-webpack-plugin
        // notice that we don't use [hash] for the stylesheet filenames in DEV: that way plugins that reload stylesheets work as expected
        new ExtractTextWebpackPlugin("[name].css", {
            disable: false,
        }),
    ],

    // Webpack Development Server configuration
    // Description: The webpack-dev-server is a little node.js Express server.
    // The server emits information about the compilation state to the client,
    // which reacts to those events.
    // reference: https://webpack.github.io/docs/webpack-dev-server.html
    devServer: {
        port: METADATA.PORT,
        host: METADATA.HOST,

        // HTML5 History API support: no need for # in URLs
        // automatically redirect 404 errors to the index.html page
        // uses connect-history-api-fallback behind the scenes: https://github.com/bripkens/connect-history-api-fallback
        // reference: http://jaketrent.com/post/pushstate-webpack-dev-server/
        historyApiFallback: true,

        // file watch configuration
        watchOptions: {
            aggregateTimeout: 300,
            poll: 1000,
        },
        contentBase: helpers.root("src/app"), // necessary so that assets are accessible

        // Can be used to add specific headers
        headers: {
            // enable CORS
            "Access-Control-Allow-Origin": "*",

            // CSP header (and its variants per browser)
            "Content-Security-Policy": cspDirectives.join("; "),
            "X-Content-Security-Policy": cspDirectives.join("; "),
            "X-WebKit-CSP": cspDirectives.join("; "),

            // Other security headers

            // protect against clickjacking: https://en.wikipedia.org/wiki/Clickjacking
            // reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/X-Frame-Options
            "X-Frame-Options": "deny",

            // enable some protection against XSS
            // reference: https://www.owasp.org/index.php/List_of_useful_HTTP_headers
            // other reference: http://blog.innerht.ml/the-misunderstood-x-xss-protection/
            "X-Xss-Protection": "1; mode=block",

            // protect against drive-by download attacks and user uploaded content that could be treated by Internet Explorer as executable or dynamic HTML files
            // reference: https://www.owasp.org/index.php/List_of_useful_HTTP_headers
            "X-Content-Type-Options": "nosniff",
        },
    },
});

// If Hot Module Replacement (HMR) is enabled but the inline option has not been specified
// then we make sure that live reloading is not enabled
// reference: https://github.com/webpack/webpack/issues/418
if(helpers.hasProcessFlag("hot") && !helpers.hasProcessFlag("inline")) {
    module.exports.entry["webpack-dev-server"] = "webpack/hot/only-dev-server";
}
<commit_msg>Removed needless comment<commit_after>"use strict";

const webpack = require("webpack");

const webpackMerge = require("webpack-merge"); // Used to merge webpack configs
const commonConfig = require("./webpack.common.js"); // common configuration between environments

// Helpers
const helpers = require("./helpers");

// Webpack Plugins
const ExtractTextWebpackPlugin = require("extract-text-webpack-plugin");

// Metadata
const METADATA = webpackMerge(commonConfig.metadata, {
    HOST: process.env.HOST || "localhost",
    PORT: process.env.PORT || 3000,
    ENV: process.env.ENV = process.env.NODE_ENV = "development",
    HMR: helpers.hasProcessFlag("hot"),
    PRODUCTION: false,
    DEVELOPMENT: true,
});

// Directives to be used in CSP header
// References
// https://developer.mozilla.org/en-US/docs/Web/Security/CSP
// https://scotthelme.co.uk/csp-cheat-sheet
const cspDirectives = [
    "base-uri 'self'",
    "default-src 'self'",
    "child-src 'self'",
    "connect-src 'self' http://my.awesome.api ws://localhost:3000",  // http://my.awesome.api is due to the mock REST api mock baseUrl and ws://localhost:3000" is due to FakeRest
    "font-src 'self'",
    "form-action 'self'",
    "frame-src 'self'",   // TODO: deprecated. Use child-src instead. Used here because child-src is not yet supported by Firefox. Remove as soon as it is fully supported
    "frame-ancestors 'none'",  // the app will not be allowed to be embedded in an iframe (roughly equivalent to X-Frame-Options: DENY)
    "img-src 'self' data: image/png",  // data: image/png" is due to Angular Material loading PNG images in base64 encoding
    "media-src 'self'",
    "object-src 'self'",
    "plugin-types application/pdf",  // valid mime-types for plugins invoked via <object> and <embed>  // TODO: not yet supported by Firefox
    "script-src 'self' 'unsafe-eval'",  // 'unsafe-eval' is due to Angular Material inline theming (see issue https://github.com/angular/material/issues/980)
    "style-src 'self' 'unsafe-inline'",  // 'unsafe-inline' is due to Angular Material inline theming (see issue https://github.com/angular/material/issues/980)
    "referrer no-referrer",
    "reflected-xss block",
    "block-all-mixed-content",
    "report-uri http://localhost"  // TODO: define an specific URL to POST the reports of policy failures
];

/*
 * Config
 * IMPORTANT: notice that the configuration below is MERGED with the common configuration (commonConfig)
 * reference: http://webpack.github.io/docs/configuration.html#cli
 */
module.exports = webpackMerge(commonConfig, {
    // static data for index.html
    metadata: METADATA,

    // Developer tool to enhance debugging
    // reference: https://webpack.github.io/docs/configuration.html#devtool
    // reference: https://github.com/webpack/docs/wiki/build-performance#sourcemaps
    devtool: "source-map",

    // Cache generated modules and chunks to improve performance for multiple incremental builds.
    // Enabled by default in watch mode.
    // You can pass false to disable it
    // reference: http://webpack.github.io/docs/configuration.html#cache
    //cache: true,

    // Switch loaders to debug mode
    // reference: http://webpack.github.io/docs/configuration.html#debug
    debug: true,

    // the entry point for the bundles
    // reference: http://webpack.github.io/docs/configuration.html#entry
    entry: {
        "polyfills": helpers.root("src/polyfills.ts"),
        "vendor-styles": helpers.root("src/vendor-styles.ts"),
        "main-styles": helpers.root("src/main-styles.ts"), // our angular app's styles. Useful only changing the styles bundle while working on styling
        "vendor": helpers.root("src/vendor.ts"),
        "main": helpers.root("src/main.ts"), // our angular app
    },

    // Options affecting the normal modules.
    // reference: http://webpack.github.io/docs/configuration.html#module
    module: {
        // An array of automatically applied loaders.
        //
        // IMPORTANT: The loaders here are resolved relative to the resource which they are applied to.
        // This means they are not resolved relative to the configuration file.
        //
        // reference: http://webpack.github.io/docs/configuration.html#module-loaders
        loaders: [
            // Support for .ts files.
            // reference: https://github.com/s-panferov/awesome-typescript-loader
            {
                test: /\.ts$/,
                loader: "awesome-typescript",
                exclude: [
                    /\.e2e\.ts$/, // exclude end-to-end tests
                    /\.spec\.ts$/, // exclude unit tests
                ],
            },
        ],
    },

    // Add additional plugins to the compiler.
    // reference: http://webpack.github.io/docs/configuration.html#plugins
    plugins: [
        // Environment helpers (when adding more properties make sure you include them in environment.d.ts)
        // Plugin: DefinePlugin
        // Description: Define free variables.
        // Useful for having development builds with debug logging or adding global constants.
        // reference: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
        // NOTE: when adding more properties make sure you include them in custom-typings.d.ts
        new webpack.DefinePlugin({
            "ENV": JSON.stringify(METADATA.ENV),
            "NODE_ENV": JSON.stringify(METADATA.ENV),
            "HMR": METADATA.HMR,
            "PRODUCTION": METADATA.PRODUCTION,
            "DEVELOPMENT": METADATA.DEVELOPMENT,
            "process.env": {
                "ENV": JSON.stringify(METADATA.ENV),
                "NODE_ENV": JSON.stringify(METADATA.ENV),
                "HMR": METADATA.HMR,
                "PRODUCTION": METADATA.PRODUCTION,
                "DEVELOPMENT": METADATA.DEVELOPMENT,
            },
        }),

        // Plugin: CommonsChunkPlugin
        // Description: Shares common code between the pages.
        // It identifies common modules and put them into a commons chunk.
        // reference: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
        // reference: https://github.com/webpack/docs/wiki/optimization#multi-page-app
        new webpack.optimize.CommonsChunkPlugin({
            name: helpers.reverse([
                "polyfills",
                "vendor",
                "main",
                "vendor-styles",
                "main-styles"
            ]),
        }),

        // Plugin: ExtractTextWebpackPlugin
        // Description: Extract css file contents
        // reference: https://github.com/webpack/extract-text-webpack-plugin
        // notice that we don't use [hash] for the stylesheet filenames in DEV: that way plugins that reload stylesheets work as expected
        new ExtractTextWebpackPlugin("[name].css", {
            disable: false,
        }),
    ],

    // Webpack Development Server configuration
    // Description: The webpack-dev-server is a little node.js Express server.
    // The server emits information about the compilation state to the client,
    // which reacts to those events.
    // reference: https://webpack.github.io/docs/webpack-dev-server.html
    devServer: {
        port: METADATA.PORT,
        host: METADATA.HOST,

        // HTML5 History API support: no need for # in URLs
        // automatically redirect 404 errors to the index.html page
        // uses connect-history-api-fallback behind the scenes: https://github.com/bripkens/connect-history-api-fallback
        // reference: http://jaketrent.com/post/pushstate-webpack-dev-server/
        historyApiFallback: true,

        // file watch configuration
        watchOptions: {
            aggregateTimeout: 300,
            poll: 1000,
        },
        contentBase: helpers.root("src/app"), // necessary so that assets are accessible

        // Can be used to add specific headers
        headers: {
            // enable CORS
            "Access-Control-Allow-Origin": "*",

            // CSP header (and its variants per browser)
            "Content-Security-Policy": cspDirectives.join("; "),
            "X-Content-Security-Policy": cspDirectives.join("; "),
            "X-WebKit-CSP": cspDirectives.join("; "),

            // Other security headers

            // protect against clickjacking: https://en.wikipedia.org/wiki/Clickjacking
            // reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/X-Frame-Options
            "X-Frame-Options": "deny",

            // enable some protection against XSS
            // reference: https://www.owasp.org/index.php/List_of_useful_HTTP_headers
            // other reference: http://blog.innerht.ml/the-misunderstood-x-xss-protection/
            "X-Xss-Protection": "1; mode=block",

            // protect against drive-by download attacks and user uploaded content that could be treated by Internet Explorer as executable or dynamic HTML files
            // reference: https://www.owasp.org/index.php/List_of_useful_HTTP_headers
            "X-Content-Type-Options": "nosniff",
        },
    },
});

// If Hot Module Replacement (HMR) is enabled but the inline option has not been specified
// then we make sure that live reloading is not enabled
// reference: https://github.com/webpack/webpack/issues/418
if(helpers.hasProcessFlag("hot") && !helpers.hasProcessFlag("inline")) {
    module.exports.entry["webpack-dev-server"] = "webpack/hot/only-dev-server";
}
<|endoftext|>


<commit_before>module.exports = {

    /**
     * Must contain at least one endpoint
     * Example:
     * {
     *      'main' : 'http://localhost/app'
     * }
     *
     */
    'endpoints' : {
        'auth': 'https://cep-fwkdemoiselle.rhcloud.com/'
    }

}<commit_msg>travis<commit_after>module.exports = {

    /**
     * Must contain at least one endpoint
     * Example:
     * {
     *      'main' : 'http://localhost/app'
     * }
     *
     */
    'endpoints': {
        'auth': 'https://cep-fwkdemoiselle.rhcloud.com/'
    }

}<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
var State = require('../state')
  , MissingStateError = require('../errors/missingstateerror');

/**
 * Complete state.
 *
 * This middleware is used to complete a stateful interaction.
 */
module.exports = function(dispatcher, store, options) {
  if (typeof options == 'string') {
    options = { name: options };
  }
  options = options || {};

  var from = options.name
    , through = options.through
  var getHandle = options.getHandle || function(req) {
    return (req.query && req.query.state) || (req.body && req.body.state);
  }

  return function completeState(req, res, next) {
    req._stateTransitions = req._stateTransitions || 0;

    function dispatch(name) {
      return dispatcher._dispatch(name, from, through, null, req, res, next);
    }

    function proceed(h, ystate) {
      if (!h) {
        // No state to resume.  `next` middleware is expected to implement
        // default behavior for responding to the request.
        return next();
      }

      store.load(req, h, function(err, state) {
        //err = new Error('wtf')
        //err.state = state

        if (err) { return next(err); }
        if (!state) {
          return (ystate)
            ? next(new MissingStateError("Failed to load previous state", h))
            : next(new MissingStateError("Failed to load state", h));
        }

        req.state = new State(req, state, h);

        if (from && from === state.name) {
          // State has been loaded for the state that is the yeilding state, and
          // therefore needs finalizing and further resumption, if possible.
          return finalize(state);
        }

        // Expose the state that is yeilding control back to the previous state.
        // When the previous state is resumed, it can use this context to inform
        // its behavior.
        req.yieldState = ystate;

        dispatch(state.name);
      });
    }

    function finalize(state) {
      // Remove the current state from any persistent storage, due to the
      // fact that it is complete.  Proceed to load the parent state (if any)
      // and resume processing.
      store.destroy(req, state.handle, function(err) {
        if (err) { return next(err); }
        return proceed(state.prev, state);
      });
    }

    // At this point, the request is ready to be dispatched to the middleware
    // chain that will resume processing of the parent state, if any.  This
    // currently executing middleware is paired with `completeError` on the
    // middleware chain for the current request.
    //
    // If an error occurs while resuming the parent state, we want to avoid a
    // double-dispatch when `completeError` is invoked.  As such, we set a flag
    // to check for that condition.  This effectively ensures that
    // `completeError` executes only for errors encountered in the processing of
    // the current state.
    req._skipResumeError = true;

    console.log('@COMPLETE # ' + req._stateTransitions);
    console.log('  name: ' + (req.state ? req.state.name : 'unloaded'))

    if (req.state) {
      //console.log(from)
      //console.log(req.state.name)

      if (from && from !== req.state.name && !req.__finishedTask) {
        // State has been loaded for a state that is not the yeilding state, and
        // therefore is the state that is being resumed.  Dispatch the request
        // to that state's resume middleware chain for processing.
        return dispatch(req.state.name);
      }

      // State has been loaded for the current, and now yeilding, state.
      // Finalize the state, removing it from any persistent storage now that
      // the state is complete and no longer needed.  Once the state has been
      // removed, the parent state (if any) will be resumed.
      return finalize(req.state);
    } else if (req._state) {
      // State has been loaded for a state that was not the expected, and now
      // yielding, state, and therefore is the state that is being resumed.
      // This is an optimization, supported by a prior call to `loadState`
      // with a specified name option.
      req.state = req._state;
      delete req._state;
      return dispatch(req.state.name);
    } else {
      return proceed(getHandle(req));
    }
  };
};
<commit_msg>Improve complete handling.<commit_after>/**
 * Module dependencies.
 */
var State = require('../state')
  , MissingStateError = require('../errors/missingstateerror');

/**
 * Complete state.
 *
 * This middleware is used to complete a stateful interaction.
 */
module.exports = function(dispatcher, store, options) {
  if (typeof options == 'string') {
    options = { name: options };
  }
  options = options || {};

  var from = options.name
    , through = options.through
  var getHandle = options.getHandle || function(req) {
    return (req.query && req.query.state) || (req.body && req.body.state);
  }

  return function completeState(req, res, next) {
    req._stateTransitions = req._stateTransitions || 0;

    function dispatch(name) {
      return dispatcher._dispatch(name, from, through, null, req, res, next);
    }

    function proceed(h, ystate) {
      if (!h) {
        // No state to resume.  `next` middleware is expected to implement
        // default behavior for responding to the request.
        return next();
      }

      store.load(req, h, function(err, state) {
        //err = new Error('wtf')
        //err.state = state

        if (err) { return next(err); }
        if (!state) {
          return (ystate)
            ? next(new MissingStateError("Failed to load previous state", h))
            : next(new MissingStateError("Failed to load state", h));
        }

        req.state = new State(req, state, h);

        if (from && from === state.name) {
          // State has been loaded for the state that is the yeilding state, and
          // therefore needs finalizing and further resumption, if possible.
          return finalize(state);
        }

        // Expose the state that is yeilding control back to the previous state.
        // When the previous state is resumed, it can use this context to inform
        // its behavior.
        req.yieldState = ystate;

        dispatch(state.name);
      });
    }

    function finalize(state) {
      // Remove the current state from any persistent storage, due to the
      // fact that it is complete.  Proceed to load the parent state (if any)
      // and resume processing.
      store.destroy(req, state.handle, function(err) {
        if (err) { return next(err); }
        return proceed(state.prev, state);
      });
    }

    // At this point, the request is ready to be dispatched to the middleware
    // chain that will resume processing of the parent state, if any.  This
    // currently executing middleware is paired with `completeError` on the
    // middleware chain for the current request.
    //
    // If an error occurs while resuming the parent state, we want to avoid a
    // double-dispatch when `completeError` is invoked.  As such, we set a flag
    // to check for that condition.  This effectively ensures that
    // `completeError` executes only for errors encountered in the processing of
    // the current state.
    req._skipResumeError = true;

    console.log('@COMPLETE # ' + req._stateTransitions);
    console.log('  name: ' + (req.state ? req.state.name : 'unloaded'))
    if (req.state) {
      //console.log('  new: ' + req.state.isNew());
      //console.log('  changed: ' + req.state.isChanged());
    }

    if (req.state) {
      //console.log(from)
      //console.log(req.state.name)

      if (from && from !== req.state.name && !req.__finishedTask) {
        // State has been loaded for a state that is not the yeilding state, and
        // therefore is the state that is being resumed.  Dispatch the request
        // to that state's resume middleware chain for processing.
        return dispatch(req.state.name);
      }

      // State has been loaded for the current, and now yeilding, state.
      // Finalize the state, removing it from any persistent storage now that
      // the state is complete and no longer needed.  Once the state has been
      // removed, the parent state (if any) will be resumed.
      if (req.state.isNew && req.state.isNew()) {
        return proceed(getHandle(req), req.state);
      } else {
        return finalize(req.state);
      }
    } else if (req._state) {
      // State has been loaded for a state that was not the expected, and now
      // yielding, state, and therefore is the state that is being resumed.
      // This is an optimization, supported by a prior call to `loadState`
      // with a specified name option.
      req.state = req._state;
      delete req._state;
      return dispatch(req.state.name);
    } else {
      return proceed(getHandle(req));
    }
  };
};
<|endoftext|>