[
  {
    "path": ".github/workflows/semgrep.yml",
    "content": "\non:\n  pull_request: {}\n  workflow_dispatch: {}\n  push: \n    branches:\n      - main\n      - master\n  schedule:\n    - cron: '0 0 * * *'\nname: Semgrep config\njobs:\n  semgrep:\n    name: semgrep/ci\n    runs-on: ubuntu-20.04\n    env:\n      SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}\n      SEMGREP_URL: https://cloudflare.semgrep.dev\n      SEMGREP_APP_URL: https://cloudflare.semgrep.dev\n      SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version\n    container:\n      image: returntocorp/semgrep\n    steps:\n      - uses: actions/checkout@v3\n      - run: semgrep ci\n"
  },
  {
    "path": ".gitignore",
    "content": ".nyc_output\ncoverage/\nnode_modules/\n.npmrc\n*.DS_Store\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright 2018 Cloudflare\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nNeither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "README.md",
    "content": "# serverless-cloudflare-workers\n\nServerless plugin for [Cloudflare Workers](https://developers.cloudflare.com/workers/)\n\n## Documentation\n\nhttps://serverless.com/framework/docs/providers/cloudflare/guide/quick-start/\n\n### Bundling with Webpack\n\nYou can have the plugin automatically bundle your code into one file using [webpack](https://webpack.js.org/). This is a great solution if you are fine with a no frills bundling.\n\nYou can use a single global webpack config to bundle your assets. And this webpack config will be built during the packaging time, before individual functions are prepared. To use this, add `webpackConfig` to your service section in serverless config, with value as the path to the webpack config.\n\n```yaml\nservice:\n  name: service-name\n  webpackConfig: webpack.config #webpack config path without js extension from root folder.\n  config:\n    accountId: ${env:CLOUDFLARE_ACCOUNT_ID}\n    zoneId: ${env:CLOUDFLARE_ZONE_ID}\n\n```\n\nYou can also add a function level webpack configuration in addition to a global webpack configuration. This helps you to process bundling different for an individual function than the global webpack config explained earlier. To use this, set the webpack config path to the function level `webpack` variable. Setting function level `webpack` variable to `true` will force webpack to bundle the function script with a default web pack configuration. Setting `webpack` key to `false` will turn off webpack for the function. (i.e the function script will not be fetched from dist folder)\n\nSimply add `webpack: true | <config path>` to your config block.\n\n```yaml\nfunctions:\n  myfunction:\n    name: myfunction\n    webpack: true #or the web pack config path for this function\n    script: handlers/myfunctionhandler\n    events:\n      - http:\n          url: example.com/myfunction\n          method: GET\n  \n```\n\n### Environment Variables\n\nWhile Cloudflare Workers doesn't exactly offer environment vairables, we can bind global variables to values, essentially giving the same capabilities. In your function configuration, add key value pairs in `environment`\n\n```yaml\nfunctions:\n  myFunction:\n    environment:\n      MYKEY: value_of_my_key\n      ANOTHER_KEY_OF_MINE: sweet_child_o_mine\n\n```\n\nThen in your script, you can reference `MYKEY` to access the value.\n\nYou can also add an environment block under `provider`. These will get added to every function. If a function defines the same variable, the function defintion will overwrite the provider block definition.\n\n```yaml\nprovider:\n  name: cloudflare\n  environment:\n    MYKEY: value_of_my_key\n    ANOTHER_KEY_OF_MINE: sweet_child_o_mine\n\n```\n\n### Using Cloudflare KV Storage\n\nThe plugin can create and bind a [KV Storage](https://developers.cloudflare.com/workers/kv/) namespace for your function by simpling adding a resources section.\n\nThe following will create a namespace called `BEST_NAMESPACE` and bind the variable `TEST` to that namespace inside `myfunction`.\n\n```yaml\nfunctions:\n  myfunction:\n    name: myfunction\n    webpack: true\n    script: handlers/myfunctionhandler\n    resources:\n      kv:\n        - variable: TEST\n          namespace: BEST_NAMESPACE\n    events:\n      - http:\n          url: example.com/myfunction\n          method: GET\n```\n\n### Web Assembly\n\nThe plugin can upload and bind WASM to execute in your worker. The easiest way to do this is to use the --template cloudflare-workers-rust when generating a project. The template includes a Rust create folder setup with wasm-pack, a webpack script for adding the generated javascript into your project, and the yml file settings to upload the wasm file itself.\n\n```yaml\nfunctions:\n  myfunction:\n    name: myfunction\n    webpack: true\n    script: handlers/myfunctionhandler\n    resources:\n      wasm:\n        - variable: WASM\n          filename: rust/pkg/wasm_bg.wasm\n    events:\n      - http:\n          url: example.com/myfunction\n          method: GET\n```"
  },
  {
    "path": "deploy/cloudflareDeploy.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst BB = require(\"bluebird\");\nconst ms = require(\"./lib/multiscript\");\nconst ss = require(\"./lib/singlescript\");\n\nconst accountType = require(\"../shared/accountType\");\nconst logs = require(\"./lib/logResponse\");\nconst utils = require(\"../utils\");\nconst validate = require(\"../shared/validate\");\nconst duplicate = require(\"../shared/duplicate\");\n\nclass CloudflareDeploy {\n  constructor(serverless, options) {\n    this.serverless = serverless;\n    this.options = options || {};\n    this.provider = this.serverless.getProvider(\"cloudflare\");\n\n    Object.assign(this, accountType, ms, utils, ss, logs, validate);\n\n    const startTime = Date.now();\n\n    this.hooks = {\n      \"deploy:deploy\": () =>\n        BB.bind(this)\n          .then(this.checkAccountType)\n          .then(async isMultiScript => {\n            this.serverless.cli.log('Starting Serverless Cloudflare-Worker deployment.');\n            if (isMultiScript && await duplicate.checkIfDuplicateRoutes(this.serverless, this.provider)) {\n              return BB.reject(\"Duplicate routes pointing to different script\");\n            }\n\n            if (this.getInvalidScriptNames()) {\n              return BB.reject(\n                \"Worker names can contain lowercase letters, numbers, underscores, and dashes. They cannot start with dashes.\"\n              );\n            }\n\n            if (isMultiScript) {\n              return this.multiScriptDeployAll()\n            } else {\n              const functionObject = this.getFunctionObjectForSingleScript();\n              return this.deploySingleScript(functionObject);\n            }\n          })\n          .then(this.logDeployResponse)\n          .then(k => this.serverless.cli.log(`Finished deployment in ${(Date.now() - startTime) / 1000} seconds.`))\n          .then(k => this.serverless.cli.log('Finished Serverless Cloudflare-Worker deployment.'))\n    };\n  }\n}\n\nmodule.exports = CloudflareDeploy;\n"
  },
  {
    "path": "deploy/cloudflareDeployFunction.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst BB = require(\"bluebird\");\nconst ms = require(\"./lib/multiscript\");\nconst ss = require(\"./lib/singlescript\");\n\nconst validateFunctionName = require(\"../shared/validate\");\nconst accountType = require(\"../shared/accountType\");\nconst utils = require(\"../utils\");\nconst logs = require(\"./lib/logResponse\");\nconst duplicate = require(\"../shared/duplicate\");\n\nclass CloudflareDeployFunction {\n  constructor(serverless, options) {\n    this.serverless = serverless;\n    this.options = options || {};\n    this.provider = this.serverless.getProvider(\"cloudflare\");\n\n    Object.assign(this, validateFunctionName, accountType, ms, utils, ss, logs);\n\n    let functionNamesForDeploy = [];\n\n    this.hooks = {\n      \"deploy:function:deploy\": () =>\n        BB.bind(this)\n          .then(this.validateFunctionName)\n          .then( (functions) => {\n            functionNamesForDeploy = functions;\n            return this.checkAccountType;\n          })\n          .then(async isMultiScript => {\n            if (isMultiScript && await duplicate.checkIfDuplicateRoutes(this.serverless, this.provider)) {\n              return BB.reject(\"Duplicate routes pointing to different script\");\n            }\n            \n            if (this.getInvalidScriptNames()) {\n              return BB.reject(\n                \"Worker names can contain lowercase letters, numbers, underscores, and dashes. They cannot start with dashes.\"\n              );\n            }\n            \n            if (isMultiScript) {\n              return this.multiScriptDeployAll(functionNamesForDeploy);\n            } else {\n              const functionObject = this.getFunctionObjectForSingleScript();\n              return this.deploySingleScript(functionObject);\n            }\n          })\n          .then(this.logDeployResponse)\n    };\n  }\n}\n\nmodule.exports = CloudflareDeployFunction;\n"
  },
  {
    "path": "deploy/lib/logResponse.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nmodule.exports = {\n  logDeployResponse({ workerScriptResponse, routesResponse, namespaceResponses, isMultiScript }) {\n    if (isMultiScript) {\n      this.aggregateWorkerResponse(this.serverless.cli, workerScriptResponse);\n      this.aggregateRoutesResponse(this.serverless.cli, routesResponse);\n    } else {\n      this.parseWorkerResponse(this.serverless.cli, workerScriptResponse);\n      this.parseRoutesResponse(this.serverless.cli, routesResponse);\n    }\n  }\n};\n"
  },
  {
    "path": "deploy/lib/multiscript.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst BB = require(\"bluebird\");\nconst webpack = require(\"../../utils/webpack\");\nconst ms = require(\"../../shared/multiscript\");\n\nmodule.exports = {\n  async deployScriptToCloudflare(functionObject) {\n    return BB.bind(this)\n      .then(async () => {\n\n        if (functionObject.webpack) {\n          await webpack.pack(this.serverless, functionObject);\n        }\n\n        // deploy script, routes, and namespaces\n        const namespaceResponse = await ms.deployNamespaces(this.provider.config.accountId, functionObject);\n        const workerScriptResponse = await ms.deployWorker(this.provider.config.accountId, this.serverless, functionObject);\n        const routesResponse = await ms.deployRoutes(this.provider.config.zoneId, functionObject);\n\n        return {\n          workerScriptResponse,\n          routesResponse,\n          namespaceResponse\n        };\n      });\n  },\n\n\n  async  deployScript(scriptName) {\n    const startScriptTime = Date.now();\n    const functionObject = this.getFunctionObject(scriptName);\n\n    this.serverless.cli.log(`deploying script: ${scriptName}`);\n    const {\n      workerScriptResponse,\n      routesResponse: rResponse,\n      namespaceResponse,\n    } = await this.deployScriptToCloudflare(functionObject, scriptName);\n\n    this.serverless.cli.log(`Finished deployment ${scriptName} in ${(Date.now() - startScriptTime) / 1000} seconds`);\n    return { workerResponse: workerScriptResponse, routesResponse: rResponse, namespaceResponse }\n  },\n\n  /**\n   * Deploy functions passed in or all functions if no functions are submitted\n   * \n   * @param {Array[string]} functions \n   */\n  async multiScriptDeployAll(functions = null) {\n\n    functions = functions || this.serverless.service.getAllFunctions();\n\n    if (typeof (functions) === 'undefined' || functions === null) {\n      throw new Error(\"Incorrect template being used for a MultiScript user \");\n    }\n\n    let workerResponse = [];\n    let routesResponse = [];\n    let namespaceResponses = [];\n\n    // Build global webpack if available\n    await webpack.packGlobalWebpack(this.serverless)\n\n    this.serverless.cli.log('Starting deployment');\n\n    // scriptName is really the key of the function map\n    for (const name of functions) {\n      const result = await this.deployScript(name);\n      workerResponse.push(result.workerResponse)\n      routesResponse.push(result.routesResponse)\n      namespaceResponses.push(result.namespaceResponse)\n    }\n\n    return {\n      workerScriptResponse: workerResponse,\n      routesResponse,\n      namespaceResponses,\n      isMultiScript: true\n    };\n  }\n};\n"
  },
  {
    "path": "deploy/lib/singlescript.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst sdk = require(\"../../provider/sdk\");\nconst { generateCode, generateWASM } = require(\"./workerScript\");\nconst BB = require(\"bluebird\");\nconst webpack = require(\"../../utils/webpack\");\nconst cf = require(\"cloudflare-workers-toolkit\");\nconst ms = require(\"../../shared/multiscript\");\n\nmodule.exports = {\n\n  async singleServeRoutesAPI({ pattern, zoneId }) {\n    const payload = { pattern, enabled: true };\n    return await sdk.cfApiCall({\n      url: `https://api.cloudflare.com/client/v4/zones/${zoneId}/workers/filters`,\n      method: `POST`,\n      contentType: `application/json`,\n      body: JSON.stringify(payload)\n    });\n  },\n\n  async getRoutesSingleScript(zoneId) {\n    return sdk.cfApiCall({\n      url: `https://api.cloudflare.com/client/v4/zones/${zoneId}/workers/filters`,\n      method: `GET`\n    });\n  },\n\n  collectRoutes(events) {\n    return events.map(event => {\n      if (event.http) {\n        return event.http.url;\n      }\n    })\n  },\n\n  /**\n   * Deploys a single script zone which can only have one script per zone.\n   * Because of this the name field is omitted.\n   * Also, zoneId must be used since it is required to deploy a single script.\n   * @param {*} functionObject \n   */\n  async deploySingleScript(functionObject) {\n    return await BB.bind(this).then(async () => {\n      const { zoneId } = this.provider.config;\n\n      const singleScriptRoutes = this.collectRoutes(functionObject.events);\n      let workerScriptResponse;\n      let routesResponse = [];\n\n      // Build global webpack if available\n      await webpack.packGlobalWebpack(this.serverless)\n\n      // If a local webpack config defined, do that too\n      if (functionObject.webpack) {\n        await webpack.pack(this.serverless, functionObject);\n      }\n\n      const scriptContents = generateCode(this.serverless, functionObject);\n\n      cf.setAccountId(this.provider.config.accountId);\n      const namespaceResponse = await ms.deployNamespaces(this.provider.config.accountId, functionObject);\n      let bindings = await ms.getBindings(this.provider, functionObject)\n\n      const response = await cf.workers.deploy({\n        accountId: this.provider.config.accountId,\n        zoneId,\n        script: scriptContents,\n        wasm: generateWASM(functionObject),\n        bindings\n      });\n\n      workerScriptResponse = response;\n\n      for (const pattern of singleScriptRoutes) {\n        this.serverless.cli.log(`deploying route: ${pattern}`);\n        const rResponse = await this.singleServeRoutesAPI({\n          pattern,\n          zoneId\n        });\n\n        routesResponse.push(rResponse);\n      }\n\n      return {\n        namespaceResponse,\n        workerScriptResponse,\n        routesResponse,\n        isMultiScript: false\n      };\n    });\n  }\n};\n"
  },
  {
    "path": "deploy/lib/workerScript.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst path = require(\"path\");\nconst fs = require(\"fs\");\nconst webpack = require(\"../../utils/webpack\");\n\nconst generateCode = (serverless, functionObject) => {\n  let { script } = functionObject;\n\n  const rootPath = webpack.getAssetPathPrefix(serverless, functionObject)\n\n  if (path.extname(script) != \".js\") {\n    script = `${rootPath}${script}.js`\n  }\n\n  return fs.readFileSync(script).toString();\n};\n\n/**\n * Builds the list of wasm objects for script deployment\n * @param {} functionObject \n */\nconst generateWASM = (functionObject) => {\n  let wasm = [];\n  if (functionObject && functionObject.resources && functionObject.resources.wasm) {\n    functionObject.resources.wasm.map((w) => {\n      wasm.push(w.file);\n    })\n  }\n  return wasm;\n}\n\nmodule.exports = {\n  generateCode,\n  generateWASM\n};\n"
  },
  {
    "path": "index.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst CloudflareDeploy = require(\"./deploy/cloudflareDeploy\");\nconst CloudflareDeployFunction = require(\"./deploy/cloudflareDeployFunction\");\nconst CloudflareRemove = require(\"./remove/cloudflareRemove\");\nconst CloudflareProvider = require(\"./provider/cloudflareProvider\");\nconst CloudflareInvoke = require(\"./invoke/cloudflareInvoke\");\n\nclass CloudflareIndex {\n  constructor(serverless, options) {\n    this.serverless = serverless;\n    this.options = options;\n\n    this.serverless.pluginManager.addPlugin(CloudflareProvider);\n    this.serverless.pluginManager.addPlugin(CloudflareDeploy);\n    this.serverless.pluginManager.addPlugin(CloudflareDeployFunction);\n    this.serverless.pluginManager.addPlugin(CloudflareRemove);\n    this.serverless.pluginManager.addPlugin(CloudflareInvoke);\n  }\n}\n\nmodule.exports = CloudflareIndex;\n"
  },
  {
    "path": "invoke/cloudflareInvoke.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\"use strict\";\nconst BB = require(\"bluebird\");\nconst sdk = require(\"../provider/sdk\");\nconst validateFunctionName = require(\"../shared/validate\");\nconst accountType = require(\"../shared/accountType\");\nconst utils = require(\"../utils\");\nconst invoke = require(\"./lib/invoke\");\n\nclass CloudflareInvoke {\n  constructor(serverless, options) {\n    this.serverless = serverless;\n    this.options = options || {};\n    this.provider = this.serverless.getProvider(\"cloudflare\");\n    Object.assign(this, utils, validateFunctionName, accountType, invoke);\n\n    this.hooks = {\n      \"invoke:invoke\": () =>\n        BB.bind(this)\n          .then(this.validateFunctionName)\n          .then(this.bakeEvent)\n          .then(async payload => {\n            return await sdk.invokeApiCall(payload);\n          })\n          .then(resp => {\n            console.log(resp);\n          })\n    };\n  }\n}\n\nmodule.exports = CloudflareInvoke;\n"
  },
  {
    "path": "invoke/lib/invoke.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nmodule.exports = {\n  bakeEvent() {\n    const functionObject = this.getFunctionObject();\n    const { events } = functionObject;\n\n    let bakedEvent = { url: \"\", headers: {}, method: \"GET\" };\n\n    events.forEach(event => {\n      const { http } = event;\n\n      Object.keys(http).forEach(httpEvent => {\n        if (httpEvent === \"url\") {\n          let urlString = http[httpEvent];\n          if (!urlString.startsWith(\"http://\") && !urlString.startsWith(\"https://\")) {\n            urlString = \"https://\" + urlString;\n          }\n          if (this.options.querystring) {\n            urlString += \"?\" + this.options.querystring;\n          }\n          bakedEvent.url = urlString;\n        } else if (httpEvent == \"headers\") {\n          Object.keys(http[httpEvent]).forEach(key => {\n            const value = http[httpEvent][key];\n            bakedEvent[\"headers\"][key] = value;\n          });\n        } else {\n          bakedEvent[httpEvent] = http[httpEvent];\n        }\n      });\n    });\n    return bakedEvent;\n  }\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"serverless-cloudflare-workers\",\n  \"version\": \"1.2.0\",\n  \"description\": \"serverless cloudflare workers \",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"nyc --reporter=html --reporter=text mocha --recursive\",\n    \"fmt\": \"eslint --fix ./deploy ./invoke ./provider ./remove ./index.js\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/cloudflare/serverless-cloudflare-workers.git\"\n  },\n  \"keywords\": [\n    \"serverless\",\n    \"serverless\",\n    \"framework\",\n    \"serverless\",\n    \"applications\",\n    \"workers\",\n    \"cloudflare\"\n  ],\n  \"dependencies\": {\n    \"bluebird\": \"^3.4.7\",\n    \"cloudflare-workers-toolkit\": \"^0.1.0\",\n    \"fs-extra\": \"^7.0.1\",\n    \"node-fetch\": \"^2.3.0\",\n    \"webpack\": \"^4.25.1\"\n  },\n  \"author\": \"serverless.com\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/cloudflare/serverless-cloudflare-workers/issues\"\n  },\n  \"homepage\": \"https://github.com/cloudflare/serverless-cloudflare-workers#readme\",\n  \"devDependencies\": {\n    \"eslint\": \"^5.13.0\",\n    \"eslint-config-prettier\": \"^2.9.0\",\n    \"eslint-plugin-prettier\": \"^2.6.2\",\n    \"mocha\": \"^5.2.0\",\n    \"nyc\": \"^13.3.0\",\n    \"proxyquire\": \"^2.1.0\"\n  }\n}\n"
  },
  {
    "path": "provider/cloudflareProvider.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\"use strict\";\nconst sdk = require(\"./sdk\");\nconst providerName = \"cloudflare\";\n\nclass CloudflareProvider {\n  static getProviderName() {\n    return providerName;\n  }\n\n  constructor(serverless) {\n    this.serverless = serverless;\n    this.provider = this;\n    this.serverless.setProvider(providerName, this);\n    this.config = this.serverless.service.provider.config || serverless.service.serviceObject.config;\n  }\n}\n\nmodule.exports = CloudflareProvider;\n"
  },
  {
    "path": "provider/credentials.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\"use strict\";\n\nconst ENV_PARAMS = [\"CLOUDFLARE_AUTH_KEY\", \"CLOUDFLARE_AUTH_EMAIL\"];\nconst REQUIRED_CREDENTIALS = ENV_PARAMS.map(s => {\n  // [\"auth_key\", \"email\"]\n  const a = s.split(\"CLOUDFLARE_\")[1];\n  return a.toLowerCase();\n});\nfunction get() {\n  const envProps = {};\n  ENV_PARAMS.forEach(envName => {\n    if (process.env[envName]) {\n      envProps[envName.split(\"CLOUDFLARE_\")[1].toLowerCase()] =\n        process.env[envName];\n    }\n  });\n  return envProps;\n}\n\nmodule.exports = {\n  get,\n  REQUIRED_CREDENTIALS\n};\n"
  },
  {
    "path": "provider/sdk.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst fetch = require('node-fetch');\n\nconst cfApiCall = async ({ url, method, contentType = null, body = null }) => {\n  if (url.substring(0, 8) !== \"https://\") {\n    url = `https://api.cloudflare.com/client/v4${url}`;\n  }\n  \n  let options = {\n    headers: {\n      \"X-Auth-Email\": process.env.CLOUDFLARE_AUTH_EMAIL,\n      \"X-Auth-Key\": process.env.CLOUDFLARE_AUTH_KEY\n    },\n    method: method\n  };\n  if (contentType) {\n    options[\"headers\"][\"Content-Type\"] = contentType;\n  }\n  if (body) {\n    options[\"body\"] = body;\n  }\n  return await fetch(url, options).then(responseBody => responseBody.json());\n};\n\nconst invokeApiCall = async ({\n  url,\n  method,\n  contentType = null,\n  body = null,\n  headers\n}) => {\n  let options = {\n    method,\n    headers\n  };\n\n  if (contentType) {\n    options[\"headers\"][\"Content-Type\"] = contentType;\n  }\n  if (body) {\n    options[\"body\"] = body;\n  }\n\n  return await fetch(url, options).then(responseBody => responseBody.text());\n};\n\nmodule.exports = {\n  cfApiCall,\n  invokeApiCall\n};\n"
  },
  {
    "path": "remove/cloudflareRemove.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst BB = require(\"bluebird\");\nconst ss = require(\"./lib/singlescript\");\nconst accountType = require(\"../shared/accountType\");\nconst cf = require(\"cloudflare-workers-toolkit\");\nconst utils = require(\"../utils\");\n\nclass CloudflareRemove {\n  constructor(serverless, options) {\n    this.serverless = serverless;\n    this.options = options;\n\n    this.provider = this.serverless.getProvider(\"cloudflare\");\n    // TODO: refactor out Object assigns. they lead to difficult code\n    Object.assign(this, accountType, utils);\n    this.hooks = {\n      \"remove:remove\": () => {\n        if (this.options.function || this.options.f) {\n          throw new Error(\"This does not support -f yet.\")\n        }\n        BB.bind(this)\n          .then(this.remove)\n          .then(resp => console.log(\"Removed\"))\n      }\n    };\n  }\n\n  async remove() {\n    const {\n      accountId,\n      zoneId,\n      routes: singleScriptEnabled\n    } = this.provider.config;\n\n    const functionKeys = this.serverless.service.getAllFunctions();\n    const multiscriptEnabled = await this.checkAccountType();\n\n    if (multiscriptEnabled) {\n      if (functionKeys === undefined || functionKeys === null) {\n        throw new Error(\n          \"Incorrect template being used for a MultiScript user \"\n        );\n      }\n\n      const { success, result, errors } = await cf.routes.getRoutes({zoneId});\n      let allRoutes = {};\n      if (success) {\n        result.forEach(r => {\n          try {\n            allRoutes[r.script].push(r.id);\n          } catch (err) {\n            allRoutes[r.script] = [r.id];\n          }\n        });\n      } else if (errors) {\n        throw new Error(errors);\n      }\n\n      const promises = [];\n      functionKeys.forEach(functionKey => {\n        let serviceName = this.getFunctionObject(functionKey).name;\n        allRoutes[serviceName].forEach(routeId => {\n          promises.push(cf.routes.remove({zoneId, routeId}));\n        });\n        promises.push(cf.workers.remove({accountId, name: serviceName}));\n      });\n      await Promise.all(promises);\n    } else {\n      await Promise.all([cf.workers.remove({zoneId: this.provider.config.zoneId}), ss.removeRoutes(zoneId)]);\n    }\n    this.serverless.cli.log(\"removed routes + scripts\");\n    return true;\n  }\n}\nmodule.exports = CloudflareRemove;\n"
  },
  {
    "path": "remove/lib/singlescript.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst sdk = require(\"../../provider/sdk\");\n\nmodule.exports = {\n  async removeRoutes(zoneId) {\n    const { success, errors, result } = await sdk.cfApiCall({\n      url: `https://api.cloudflare.com/client/v4/zones/${zoneId}/workers/filters`,\n      contentType: `application/json`\n    });\n    if (success) {\n      let promises = [];\n      result.forEach(filter => {\n        promises.push(\n          sdk.cfApiCall({\n            url: `https://api.cloudflare.com/client/v4/zones/${zoneId}/workers/filters/${\n              filter[\"id\"]\n            }`,\n            method: `DELETE`\n          })\n        );\n      });\n      return await Promise.all(promises);\n    }\n    throw new Error(errors);\n  }\n};\n"
  },
  {
    "path": "shared/accountType.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst BB = require(\"bluebird\");\nconst credentials = require(\"../provider/credentials\");\nconst cf = require(\"cloudflare-workers-toolkit\");\n\nmodule.exports = {\n  async checkAccountType() {\n    const zoneId = this.provider.config.zoneId;\n    return await BB.bind(this)\n      .then(this.checkAllEnvironmentVariables)\n      .then(function() {\n        return cf.workers.getSettings({zoneId});\n      })\n      .then(this.checkIfMultiScript)\n  },\n\n  checkAllEnvironmentVariables() {\n    const envCreds = credentials.get();\n    const requiredCredentials = credentials.REQUIRED_CREDENTIALS;\n    requiredCredentials.forEach(requiredCredential => {\n      if (!envCreds[requiredCredential]) {\n        return BB.reject(\n          `Missing mandatory environment variable: CLOUDFLARE_${requiredCredential.toUpperCase()}.`\n        );\n      }\n    });\n  },\n  checkIfMultiScript({ success, errors, result }) {\n    if (!success) {\n      return BB.reject(JSON.stringify(errors));\n    }\n    const { multiscript, enabled } = result;\n    if (!enabled) {\n      return BB.reject(\n        \"Workers are not enabled for this account, please upgrade your account at https://cloudflare.com\"\n      );\n    }\n\n    return multiscript;\n  }\n};\n"
  },
  {
    "path": "shared/duplicate.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst cf = require(\"cloudflare-workers-toolkit\");\n\nmodule.exports = {\n  /**\n   * @param {*} serverless\n   * @param {*} provider\n   */\n  async checkIfDuplicateRoutes(serverless, provider) {\n    // for any worker that we are uploading, we check its routes in the yml file and\n    // check if there are exact same routes in our cloudflare account which point to\n    // different script name\n    if (typeof(provider) == 'undefined' || !provider.config) {\n      throw(\"No config found.\")\n    }\n\n    const { zoneId } = provider.config;\n\n    if (!zoneId) {\n      throw(\"You must specify a Zone ID CLOUDFLARE_ZONE_ID\");\n    }\n    const response = await cf.routes.getRoutes({zoneId});\n    const { result } = response;\n      \n    // check for all the workers we are uploading\n    const foundDuplicate = result.some(filters => {\n      const { pattern, script } = filters;\n\n      const functions = serverless.service.getAllFunctions();\n      for (const scriptName of functions) {\n        const functionObject = serverless.service.getFunction(scriptName);\n        const routes = functionObject.events.map(function(event) {\n          if (event.http) {\n            return event.http.url;\n          }\n        })\n        \n        //let uploadedName = functionObject.name || scriptName;\n        return routes.some(r => {\n          return r === pattern && functionObject.name !== script;\n        });\n      }\n    });\n\n    return foundDuplicate;\n  }\n}"
  },
  {
    "path": "shared/multiscript.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst cf = require(\"cloudflare-workers-toolkit\");\nconst path = require(\"path\");\nconst { generateCode, generateWASM } = require(\"../deploy/lib/workerScript\");\n\nmodule.exports = {\n  getRoutes(events) {\n    return events.map(function (event) {\n      if (event.http) {\n        return event.http.url;\n      }\n    });\n  },\n\n  /**\n   * Parses the resources and environment config to build bindings for the worker. async because it has to get namespaces for the CF id\n   * @param {*} provider\n   * @param {*} functionObject \n   */\n  async getBindings(provider, functionObject) {\n\n    let bindings = [];\n\n    let resources = functionObject.resources;\n\n    if (resources && resources.kv) { // do nothing if there is no kv config\n      const namespaces = await cf.storage.getNamespaces();\n\n      let namespaceBindings = resources.kv.map(function (store) {\n        return {\n          name: store.variable,\n          type: 'kv_namespace',\n          namespace_id: namespaces.find(function (ns) {\n            return ns.title === store.namespace;\n          }).id\n        }\n      });\n\n      bindings = bindings.concat(namespaceBindings);\n    }\n\n    if (resources && resources.wasm) {\n      let wasmBindings = resources.wasm.map(function(wasm) {\n        return {\n          name: wasm.variable,\n          type: 'wasm_module',\n          part: path.basename(wasm.file, path.extname(wasm.file))\n        }\n      });\n\n      bindings = bindings.concat(wasmBindings);\n    }\n\n    // Get Environment Variables\n    let envVars = Object.assign({}, provider.environment);\n    envVars = Object.assign(envVars, functionObject.environment);\n\n    for (const key in envVars) {\n      bindings.push({\n        name: key,\n        type: 'secret_text',\n        text: envVars[key]\n      });\n    }\n\n    return bindings;\n  },\n\n  /**\n   * Deploys the Worker Script in functionObject from the yml file\n   * @param {*} accountId\n   * @param {*} service\n   * @param {*} functionObject \n   */\n  async deployWorker(accountId, serverless, functionObject) {\n    const { service } = serverless;\n    cf.setAccountId(accountId);\n\n    const contents = generateCode(serverless, functionObject);\n    let bindings = await this.getBindings(service.provider, functionObject);\n\n    let t = await cf.workers.deploy({\n      accountId,\n      name: functionObject.name,\n      script: contents,\n      wasm: generateWASM(functionObject),\n      bindings\n    })\n\n    return t;\n  },\n\n  /**\n   * Deploys the namespaces in function Object listed under resources->storage\n   * @param {*} accountId \n   * @param {*} functionObject \n   */\n  async deployNamespaces(accountId, functionObject) {\n    let responses = [];\n\n    if (functionObject.resources && functionObject.resources.kv) {\n      for (const store of functionObject.resources.kv) {\n        let result = await cf.storage.createNamespace({\n          accountId,\n          name: store.namespace\n        });\n        if (cf.storage.isDuplicateNamespaceError(result)) {\n          result.success = true;\n        }\n        responses.push(result);\n      }\n    }\n\n    return responses;\n  },\n\n  /**\n   * Deploys all routes found in functionObject.events\n   * @param {*} zoneId \n   * @param {*} functionObject \n   */\n  async deployRoutes(zoneId, functionObject) {\n    const allRoutes = this.getRoutes(functionObject.events);\n    let routeResponses = [];\n    for (const pattern of allRoutes) {\n      const response = await cf.routes.deploy({ path: pattern, scriptName: functionObject.name, zoneId });\n      routeResponses.push(response)\n    }\n\n    return routeResponses;\n  }\n}"
  },
  {
    "path": "shared/validate.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nconst BB = require(\"bluebird\");\n\nmodule.exports = {\n  validateFunctionName() {\n    return BB.bind(this)\n      .then(this.checkIfFuntionParamPresent)\n      .then(this.checkFunctionName);\n  },\n  checkIfFuntionParamPresent() {\n    let funParam = this.options.function;\n\n    if (funParam === undefined) {\n      funParam = this.options.f;\n    }\n\n    if (funParam === undefined || funParam === null || funParam === \"\") {\n      return BB.reject(\"Invoke function with -f or --function\");\n    }\n    return funParam;\n  },\n\n  /**\n   * Ensures that funParam is an array of functions and ensures there are config entries for each.\n   */\n  checkFunctionName(funParam) {\n    const functions = this.serverless.service.getAllFunctions();\n    if (!Array.isArray(funParam)) {\n      funParam = Array(funParam)\n    }\n    for (let func of funParam) {\n      if (functions.indexOf(func) === -1) {\n        return BB.reject(`The specified function: ${func} was not found in your configuration file.`);\n      }\n    }\n\n    return funParam;\n  },\n\n  isValidScriptName(sname) {\n    const re = new RegExp(\"^[a-z0-9_][A-Za-z0-9-_]*$\");\n    if (re.exec(sname)) {\n      return true;\n    }\n    return false;\n  },\n  \n  getInvalidScriptNames() {\n    const functions = this.serverless.service.getAllFunctions();\n    const notValidScriptNames = functions.find(scriptName => {\n      return !this.isValidScriptName(scriptName);\n    });\n    return notValidScriptNames;\n  }\n};\n"
  },
  {
    "path": "test/shared/duplicate_test.js",
    "content": "const proxyquire =  require('proxyquire')\nconst assert = require('assert');\n\nconst validate = proxyquire(\"../../shared/duplicate\", {\n  'cloudflare-workers-toolkit': {\n    \"routes\": {\n      'getRoutes': function() {\n        return Promise.resolve({\n          \"result\": [{\n            pattern: \"route1\",\n            script: \"existing\"\n          }]\n        })\n      }\n    }\n  }\n});\n\ndescribe(\"checkIfDuplicateRoutes\", function() {\n  it(\"should fail gracefully if no config is provided\", async function() {\n    try {\n      await validate.checkIfDuplicateRoutes();\n    } catch (e) {\n      assert.equal(e, \"No config found.\");\n    }\n  });\n\n  const PROVIDER = {\n    config: {\n      accountId: 12,\n      zoneId: 13\n    }\n  }\n\n  const FUNCTIONS = [\"first\", \"second\"];\n  const SERVERLESS = {\n    service: {\n      getAllFunctions: function() {\n        return FUNCTIONS;\n      },\n      getFunction: function(name) {\n        return {\n          webpack: false,\n          name: name,\n          script: `test/handlers/${name}`,\n          events: [ { http: {url: \"route1\", method: 'GET'}} ]\n        }\n      }\n    }\n  }\n  \n  it(\"should detect duplicates in the same yml file\", async function() {\n    const result = await validate.checkIfDuplicateRoutes(SERVERLESS, PROVIDER);\n    assert.equal(result, true)\n  });\n});"
  },
  {
    "path": "test/shared/multiscript_test.js",
    "content": "const proxyquire =  require('proxyquire')\nconst assert = require('assert');\n\nconst ms = proxyquire(\"../../shared/multiscript\", {\n  \"cloudflare-workers-toolkit\": {\n    \n  }\n});\n\nconst EVENTS = [{\n  'http': {\n    url: 'somedomain.com/route1',\n    method: 'GET'\n  }\n}, {\n  'http': {\n    url: 'somedomain.com/route2',\n    method: 'GET'\n  }\n}];\n\ndescribe(\"getRoutes\", function() {\n  it(\"pulls routes out of the event config\", function() {\n    const routes = ms.getRoutes(EVENTS);\n    assert.deepEqual(routes, ['somedomain.com/route1', 'somedomain.com/route2'])\n  });\n});"
  },
  {
    "path": "utils/index.js",
    "content": "/**\n * Copyright (c) 2018, Cloudflare. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n *  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nmodule.exports = {\n  getFunctionObject(paramName) {\n    let funParam = paramName || this.options.function;\n    if (typeof funParam === \"undefined\") {\n      funParam = this.options.f;\n    }\n    if (funParam) {\n      return this.serverless.service.getFunction(funParam);\n    } else return null;\n  },\n  getFunctionObjectForSingleScript() {\n    const [functionName] = this.serverless.service.getAllFunctions();\n    return this.getFunctionObject(functionName);\n  },\n  parseWorkerResponse(serverlessConsole, apiResponse) {\n    let {\n      success: workerDeploySuccess,\n      result: workerResult,\n      errors: workerErrors\n    } = apiResponse;\n\n    const { id, size } = workerResult || {};\n\n    if (workerDeploySuccess) {\n      serverlessConsole.log(\n        `✅  Script Deployed. Name: ${id}, Size: ${(size / 1024).toFixed(2)}K`\n      );\n    } else {\n      serverlessConsole.log(`❌ Fatal Error, Script Not Deployed!`);\n      workerErrors.forEach(err => {\n        let { code, message } = err;\n        serverlessConsole.log(\n          `--> Error Code:${code}\\n--> Error Message: \"${message}\"`\n        );\n      });\n    }\n    return { workerDeploySuccess, workerResult, workerErrors };\n  },\n  aggregateWorkerResponse(serverlessConsole, apiResponse) {\n    let status = [];\n    apiResponse.forEach(resp => {\n      status.push(this.parseWorkerResponse(serverlessConsole, resp));\n    });\n    return status;\n  },\n\n  parseRoutesResponse(serverlessConsole, apiResponse) {\n    let status = [];\n    apiResponse.forEach(resp => {\n      let {\n        success: routeSuccess,\n        result: routeResult,\n        errors: routeErrors\n      } = resp;\n\n      if (routeSuccess || !this.routeContainsFatalErrors(routeErrors)) {\n        serverlessConsole.log(`✅  Routes Deployed `);\n      } else {\n        serverlessConsole.log(`❌  Fatal Error, Routes Not Deployed!`);\n        routeErrors.forEach(err => {\n          let { code, message } = err;\n          serverlessConsole.log(\n            `--> Error Code:${code}\\n--> Error Message: \"${message}\"`\n          );\n        });\n      }\n\n      status.push({ routeSuccess, routeResult, routeErrors });\n    });\n    return status;\n  },\n\n  aggregateRoutesResponse(serverlessConsole, apiResponse) {\n    let status = [];\n\n    apiResponse.forEach(resp => {\n      status.push(this.parseRoutesResponse(serverlessConsole, resp));\n    });\n\n    return status;\n  },\n\n  routeContainsFatalErrors(errors) {\n    // suppress 10020 duplicate routes error\n    // no need to show error when they are simply updating their script\n    return errors.some(e => e.code !== 10020);\n  }\n};\n"
  },
  {
    "path": "utils/webpack.js",
    "content": "const path = require(\"path\");\nconst BB = require(\"bluebird\");\nconst webpack = BB.promisify(require(\"webpack\"));\nconst fse = require(\"fs-extra\");\n\nfunction getDefaultWebPackConfig(serverless, functionObject) {\n  const outputPath = path.join(\n    serverless.config.servicePath,\n    functionObject.script\n  );\n\n  return {\n    config: {\n      entry: {\n        out: outputPath\n      },\n      output: {\n        filename: `${functionObject.script}.js`,\n        path: path.join(serverless.config.servicePath, \"dist\")\n      },\n      devtool: \"cheap-module-source-map\",\n      target: \"webworker\",\n      mode: \"production\"\n    },\n    outputPath\n  };\n}\n\nasync function build(config) {\n  try {\n    let result = await webpack(config);\n    let errors = result.compilation.errors;\n    if (Array.isArray(errors) && errors) {\n      errors.forEach(error => {\n        console.log(`Webpack Error: ${error}`);\n      });\n    }\n  } catch (error) {\n    // failed to webpack\n    console.log(`Webpack Error: ${error}`);\n  }\n}\n\nmodule.exports = {\n  pack: async function (serverless, functionObject, webpackConfigFile = null) {\n    serverless.cli.log(`bundling: ${functionObject.script}`);\n    const startTime = Date.now()\n    let config = null, outputPath = '';\n\n    //If webpack config file is provided use that\n    if (webpackConfigFile && typeof webpackConfigFile === 'string') {\n      console.log(`Building web pack with config ${webpackConfigFile}.js`)\n      config = require(path.resolve(\"./\" + webpackConfigFile));\n    } else if (typeof (functionObject.webpack) === 'boolean' && functionObject.webpack) {\n      //webpack is set to true in function object. Let's generate bundle for just this function\n      console.log(`Building web pack with config default config for ${functionObject.script}`);\n      ({ config, outputPath } = getDefaultWebPackConfig(serverless, functionObject));\n    } else if (typeof (functionObject.webpack) === 'string' && functionObject.webpack) {\n      //function has individual webpack config. Build that\n      console.log(`Building web pack with config file ${functionObject.webpack} for ${functionObject.script}`);\n      ({ config } = getDefaultWebPackConfig(serverless, functionObject));\n      config = Object.assign(config, require(path.resolve(\"./\" + functionObject.webpack)));\n    }\n\n    if (!config) {\n      //No config found, probably did a global webpack build. Exit\n      return\n    }\n\n    await build(config)\n\n    console.log(`Webpack finished in ${(Date.now() - startTime) / 1000} seconds`)\n    if (outputPath) {\n      fse.removeSync(outputPath);\n    }\n\n  },\n\n  packGlobalWebpack: async function (serverless) {\n    // Let's see if there is global webpack that we need to build\n    const globalWebPackConfig = serverless.service.serviceObject.webpackConfig;\n    if (globalWebPackConfig && typeof globalWebPackConfig === 'string') {\n      await this.pack(serverless, { script: 'Global web pack config' }, globalWebPackConfig);\n    }\n  },\n\n\n  getAssetPathPrefix: function (serverless, functionObject) {\n    // If web pack is used and not explicitly turned off for this script, append dist in-front of the path\n    return (serverless.service.serviceObject.webpackConfig || functionObject.webpack) &&\n      functionObject.webpack !== false ?\n      './dist/' : '';\n  }\n};\n"
  }
]