[
  {
    "path": ".eslintignore",
    "content": "src/types/global.d.ts\r\nbenchmark/\r\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"root\": true,\n  \"parser\": \"@typescript-eslint/parser\",\n  \"plugins\": [\n    \"@typescript-eslint\",\n    \"eslint-plugin-tsdoc\"\n  ],\n  \"parserOptions\": {\n    \"project\": [\n      \"./tsconfig.eslint.json\"\n    ]\n  },\n  \"extends\": [\n    \"eslint:recommended\",\n    \"plugin:node/recommended\",\n    \"plugin:import/recommended\",\n    \"plugin:import/typescript\",\n    \"plugin:@typescript-eslint/eslint-recommended\",\n    \"plugin:@typescript-eslint/recommended\",\n    \"plugin:@typescript-eslint/recommended-requiring-type-checking\",\n    \"plugin:prettier/recommended\"\n  ],\n  \"rules\": {\n    \"tsdoc/syntax\": \"error\",\n    \"prettier/prettier\": \"warn\",\n    \"comma-dangle\": [\n      \"error\",\n      \"always-multiline\"\n    ],\n    \"node/no-missing-import\": \"off\",\n    \"node/no-empty-function\": \"off\",\n    \"node/no-unsupported-features/es-syntax\": \"off\",\n    \"node/no-missing-require\": \"off\",\n    \"node/shebang\": \"off\",\n    \"import/order\": [\n      \"error\",\n      {\n        \"newlines-between\": \"never\"\n      }\n    ],\n    \"sort-imports\": [\n      \"error\",\n      {\n        \"ignoreDeclarationSort\": true\n      }\n    ],\n    \"@typescript-eslint/no-use-before-define\": \"off\",\n    \"quotes\": [\n      \"warn\",\n      \"single\",\n      {\n        \"avoidEscape\": true\n      }\n    ],\n    \"curly\": [\n      \"error\",\n      \"multi-or-nest\"\n    ],\n    \"max-len\": [\n      \"warn\",\n      {\n        \"code\": 140,\n        \"tabWidth\": 2,\n        \"ignoreStrings\": true,\n        \"ignoreTemplateLiterals\": true,\n        \"ignoreUrls\": true,\n        \"ignoreComments\": true,\n        \"ignorePattern\": \"^import\\\\s.+\\\\sfrom\\\\s.+;$\"\n      }\n    ],\n    \"no-case-declarations\": \"warn\",\n    \"no-control-regex\": \"off\",\n    \"node/no-unpublished-import\": \"off\",\n    \"@typescript-eslint/no-namespace\": \"off\",\n    \"@typescript-eslint/no-unsafe-argument\": \"off\",\n    \"@typescript-eslint/no-unsafe-assignment\": \"off\",\n    \"@typescript-eslint/no-unsafe-member-access\": \"off\",\n    \"@typescript-eslint/no-unsafe-call\": \"off\",\n    \"@typescript-eslint/no-unsafe-return\": \"off\",\n    \"@typescript-eslint/no-var-requires\": \"off\",\n    \"@typescript-eslint/ban-ts-comment\": \"off\",\n    \"@typescript-eslint/no-explicit-any\": \"off\",\n    \"@typescript-eslint/no-non-null-assertion\": \"off\",\n    \"@typescript-eslint/restrict-template-expressions\": \"off\",\n    \"@typescript-eslint/no-floating-promises\": \"off\",\n    \"@typescript-eslint/explicit-module-boundary-types\": \"off\",\n    \"@typescript-eslint/no-inferrable-types\": \"off\",\n    \"@typescript-eslint/no-unnecessary-type-assertion\": \"off\",\n    \"@typescript-eslint/no-redundant-type-constituents\": \"off\",\n    \"@typescript-eslint/no-unused-vars\": [\n      \"error\",\n      {\n        \"varsIgnorePattern\": \"^_\",\n        \"argsIgnorePattern\": \"^_\"\n      }\n    ],\n    \"@typescript-eslint/member-ordering\": [\n      \"error\",\n      {\n        \"default\": [\n          // Constructors\n          \"public-constructor\",\n          \"protected-constructor\",\n          \"private-constructor\",\n          // Index signature\n          \"signature\",\n          // Fields\n          \"protected-abstract-field\",\n          \"public-abstract-field\",\n          \"protected-static-field\",\n          \"public-static-field\",\n          \"private-static-field\",\n          \"protected-decorated-field\",\n          \"public-decorated-field\",\n          \"private-decorated-field\",\n          \"protected-instance-field\",\n          \"public-instance-field\",\n          \"private-instance-field\",\n          // Getters\n          \"protected-decorated-get\",\n          \"public-decorated-get\",\n          \"private-decorated-get\",\n          \"protected-static-get\",\n          \"public-static-get\",\n          \"private-static-get\",\n          \"protected-instance-get\",\n          \"public-instance-get\",\n          \"private-instance-get\",\n          \"protected-abstract-get\",\n          \"public-abstract-get\",\n          \"decorated-get\",\n          \"abstract-get\",\n          \"protected-get\",\n          \"public-get\",\n          \"private-get\",\n          \"static-get\",\n          \"instance-get\",\n          \"get\",\n          // Setters\n          \"protected-abstract-set\",\n          \"public-abstract-set\",\n          \"abstract-set\",\n          \"protected-decorated-set\",\n          \"public-decorated-set\",\n          \"private-decorated-set\",\n          \"protected-static-set\",\n          \"public-static-set\",\n          \"private-static-set\",\n          \"protected-instance-set\",\n          \"public-instance-set\",\n          \"private-instance-set\",\n          \"protected-set\",\n          \"public-set\",\n          \"private-set\",\n          \"decorated-set\",\n          \"static-set\",\n          \"instance-set\",\n          \"set\",\n          // Methods\n          \"public-static-method\",\n          \"protected-static-method\",\n          \"private-static-method\",\n          \"public-decorated-method\",\n          \"protected-decorated-method\",\n          \"private-decorated-method\",\n          \"public-abstract-method\",\n          \"protected-abstract-method\",\n          \"public-instance-method\",\n          \"protected-instance-method\",\n          \"private-instance-method\"\n        ]\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Set the repository to show as TypeScript rather than JS in GitHub\n*.js linguist-detectable=false"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: \"🐛 Bug Report\"\nabout: Report a reproducible bug or regression.\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n## Current Behavior\n\n<!-- Describe how the issue manifests. -->\n\n## Expected Behavior\n\n<!-- Describe what the desired behavior would be. -->\n\n## Steps to Reproduce the Problem\n\n  1.\n  1.\n  1.\n\n## Environment\n\n- Version: <!-- Version set in package.json -->\n- Platform: <!-- Win/Mac/Linux -->\n- Node.js Version: <!-- Output of running `node -v` -->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "# This file is automatically added by @npmcli/template-oss. Do not edit.\n\nblank_issues_enabled: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: 🌈 Feature request\nabout: Suggest an amazing new idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n## Feature Request\n\n**Is your feature request related to a problem? Please describe.**\n<!-- A clear and concise description of what the problem is. Ex. I have an issue when [...] -->\n\n**Describe the solution you'd like**\n<!-- A clear and concise description of what you want to happen. Add any considered drawbacks. -->\n\n**Describe alternatives you've considered**\n<!-- A clear and concise description of any alternative solutions or features you've considered. -->\n\n## Are you willing to resolve this issue by submitting a Pull Request?\n\n<!--\n  Remember that first-time contributors are welcome! 🙌\n-->\n\n- [ ] Yes, I have the time, and I know how to start.\n- [ ] Yes, I have the time, but I don't know how to start. I would need guidance.\n- [ ] No, I don't have the time, although I believe I could do it if I had the time...\n- [ ] No, I don't have the time and I wouldn't even know how to start.\n\n<!--\n  👋 Have a great day and thank you for the feature request!\n-->\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\n  😀 Wonderful!  Thank you for opening a pull request.\n\n  Please fill in the information below to expedite the review\n  and (hopefully) merge of your change.\n-->\n\n### Description of change\n\n<!--\n  Please be clear and concise what the change is intended to do,\n  why this change is needed, and how you've verified that it\n  corrects what you intended.\n\n  In some cases it may be helpful to include the current behavior\n  and the new behavior.\n\n  If the change is related to an open issue, you can link it here.\n  If you include `Fixes #0000` (replacing `0000` with the issue number)\n  when this is merged it will automatically mark the issue as fixed and\n  close it.\n-->\n\n### Pull-Request Checklist\n\n<!--\n  Please make sure to review and check all of the following.\n\n  If an item is not applicable, you can add \"N/A\" to the end.\n-->\n\n- [ ] Code is up-to-date with the `main` branch\n- [ ] `npm run lint` passes with this change\n- [ ] `npm run test` passes with this change\n- [ ] This pull request links relevant issues as `Fixes #0000`\n- [ ] There are new or updated unit tests validating the change\n- [ ] Added documentation inside `www/docs/main` folder.\n- [ ] Included new files inside `index.doc.ts`.\n- [ ] The new commits follow conventions outlined in the [conventional commit spec](https://www.conventionalcommits.org/en/v1.0.0/)\n\n<!--\n  🎉 Thank you for contributing!\n-->\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# This file is automatically added by @npmcli/template-oss. Do not edit.\n\nversion: 2\n\nupdates:\n  - package-ecosystem: npm\n    directory: /\n    schedule:\n      interval: daily\n    allow:\n      - dependency-type: direct\n    versioning-strategy: increase-if-necessary\n    commit-message:\n      prefix: deps\n      prefix-development: chore\n    labels:\n      - \"Dependencies\"\n"
  },
  {
    "path": ".github/settings.yml",
    "content": "# This file is automatically added by @npmcli/template-oss. Do not edit.\n\nrepository:\n  allow_merge_commit: false\n  allow_rebase_merge: true\n  allow_squash_merge: true\n  squash_merge_commit_title: PR_TITLE\n  squash_merge_commit_message: PR_BODY\n  delete_branch_on_merge: true\n  enable_automated_security_fixes: true\n  enable_vulnerability_alerts: true\n\nbranches:\n  - name: main\n    protection:\n      required_status_checks: null\n      enforce_admins: true\n      required_pull_request_reviews:\n        require_last_push_approval: true\n        dismiss_stale_reviews: true\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "name: CodeQL\n\non:\n  push:\n    paths:\n      - 'src/**'\n      - 'package-lock.json'\n      - 'package.json'\n      - 'tsconfig.json'\n      - 'tsconfig.*.json'\n      - 'vite.config.ts'\n    branches:\n      - main\n  pull_request:\n    paths:\n      - 'src/**'\n      - 'package-lock.json'\n      - 'package.json'\n      - 'tsconfig.json'\n      - 'tsconfig.*.json'\n      - 'vite.config.ts'\n    branches:\n      - main\n  schedule:\n    # \"At 10:00 UTC (03:00 PT) on Monday\" https://crontab.guru/#0_10_*_*_1\n    - cron: \"0 10 * * 1\"\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    timeout-minutes: 120\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'javascript-typescript' ]\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Setup Git User\n        run: |\n          git config --global user.email \"h4ad+bot@viniciusl.com.br\"\n          git config --global user.name \"H4ad CLI robot\"\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v3\n        with:\n          languages: ${{ matrix.language }}\n\n      - name: Autobuild\n        uses: github/codeql-action/autobuild@v3\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v3\n        with:\n          category: \"/language:${{matrix.language}}\"\n"
  },
  {
    "path": ".github/workflows/docs.yml",
    "content": "name: Deploy to GitHub Pages\r\n\r\non:\r\n  push:\r\n    branches:\r\n      - main\r\n    paths:\r\n      - '.github/workflows/docs.yml'\r\n      - 'www/**'\r\n      - 'src/**'\r\n      - 'scripts/**'\r\n  workflow_dispatch:\r\n\r\njobs:\r\n  deploy:\r\n    runs-on: ubuntu-latest\r\n    permissions:\r\n      contents: write\r\n    concurrency:\r\n      group: ${{ github.workflow }}-${{ github.ref }}\r\n    steps:\r\n      - uses: actions/checkout@v4\r\n\r\n      - name: Setup Node\r\n        uses: actions/setup-node@v4\r\n        with:\r\n          node-version: '18.x'\r\n\r\n      - name: Cache dependencies\r\n        uses: actions/cache@v3\r\n        with:\r\n          path: ~/.npm\r\n          key: ${{ runner.os }}-node-18-${{ hashFiles('**/package-lock.json') }}\r\n          restore-keys: |\r\n            ${{ runner.os }}-node-18-\r\n\r\n      - name: Install Lib Dependencies\r\n        run: npm ci\r\n\r\n      - name: Install Docs Dependencies\r\n        run: npm ci\r\n        working-directory: www\r\n\r\n      - name: Parse TSDoc Documentation\r\n        run: npm run docs:generate\r\n\r\n      - name: Build Docs\r\n        run: npm run build\r\n        working-directory: www\r\n\r\n      - name: Deploy\r\n        uses: peaceiris/actions-gh-pages@v3\r\n        if: ${{ github.ref == 'refs/heads/main' }}\r\n        with:\r\n          github_token: ${{ secrets.GITHUB_TOKEN }}\r\n          publish_dir: ./www/build\r\n\r\n"
  },
  {
    "path": ".github/workflows/pr.yml",
    "content": "name: Pull Request\n\non:\n  workflow_dispatch:\n  pull_request:\n    paths:\n      - 'src/**'\n      - 'package-lock.json'\n      - 'package.json'\n      - 'tsconfig.json'\n      - 'tsconfig.*.json'\n      - 'vite.config.ts'\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [18.x, 20.x]\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Use Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node-version }}\n\n      - name: Update NPM Version\n        run: npm i -g npm\n\n      - name: Cache dependencies\n        uses: actions/cache@v3\n        with:\n          path: ~/.npm\n          key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}\n          restore-keys: |\n            ${{ runner.os }}-node-${{ matrix.node-version }}-\n\n      - name: Install Lib Dependencies\n        run: npm ci\n\n      - name: Build\n        run: npm run build\n\n      - name: Run tests\n        run: npm test\n\n      - name: Get Coverage Info\n        uses: codecov/codecov-action@v4\n        with:\n          fail_ci_if_error: true\n        env:\n          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}\n\n  docs:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Use Node.js 18\n        uses: actions/setup-node@v4\n        with:\n          node-version: '18.x'\n\n      - name: Cache dependencies\n        uses: actions/cache@v3\n        with:\n          path: ~/.npm\n          key: ${{ runner.os }}-node-18.x-${{ hashFiles('**/package-lock.json') }}\n          restore-keys: |\n            ${{ runner.os }}-node-18.x-\n\n      - name: Install Lib Dependencies\n        run: npm ci\n\n      - name: Install Docs Dependencies\n        run: npm ci\n        working-directory: www\n\n      - name: Parse TSDoc Documentation\n        run: npm run docs:generate\n\n      - name: Build Docs\n        run: npm run build\n        working-directory: www\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  push:\n    branches:\n      - main\n\npermissions:\n  contents: write\n  pull-requests: write\n  id-token: write\n\njobs:\n  release-please:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@v4\n\n      - name: Release Please\n        uses: google-github-actions/release-please-action@v4\n        id: release\n\n      - name: Use Node 20.x\n        uses: actions/setup-node@v4\n        if: ${{ steps.release.outputs.release_created }}\n        with:\n          node-version: 20\n          registry-url: 'https://registry.npmjs.org'\n\n      - name: Install Deps\n        run: npm ci\n        if: ${{ steps.release.outputs.release_created }}\n\n      - name: Build\n        run: npm run build\n        if: ${{ steps.release.outputs.release_created }}\n\n      - name: Test\n        run: npm run test\n        if: ${{ steps.release.outputs.release_created }}\n\n      - name: Get Coverage Info\n        if: ${{ steps.release.outputs.release_created }}\n        uses: codecov/codecov-action@v4\n        env:\n          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}\n\n      - name: NPM Publish\n        run: npm publish --provenance --access public\n        if: ${{ steps.release.outputs.release_created }}\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\nvar\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env.test\n.env.local\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v2\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n\n# Compiled code\nlib/\n\n# IDEs\n.idea\n\n# tsdoc\ntemp\n/etc\n!etc/.gitkeep\n\n# docs\nwww/api/*\n!www/api/.gitkeep\n\n.env\nperf/\n"
  },
  {
    "path": ".husky/.gitignore",
    "content": "_\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpm run build\nnpm run test\nnpm run lint\n"
  },
  {
    "path": ".husky/prepare-commit-msg",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nexec </dev/tty && node_modules/.bin/cz --hook || true\n"
  },
  {
    "path": ".npmrc",
    "content": "; This file is automatically added by @npmcli/template-oss. Do not edit.\n\nignore-scripts=true\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\",\n  \"arrowParens\": \"avoid\",\n  \"printWidth\": 80\n}\n"
  },
  {
    "path": ".release-please-manifest.json",
    "content": "{\n  \".\": \"4.4.0\"\n}\n"
  },
  {
    "path": ".tmuxinator.yml",
    "content": "# ./.tmuxinator.yml\n\nname: serverless-adapter\nroot: ./\n\n# Optional tmux socket\n# socket_name: foo\n\n# Note that the pre and post options have been deprecated and will be replaced by\n# project hooks.\n\n# Project hooks\n\n# Runs on project start, always\n# on_project_start: command\n\n# Run on project start, the first time\n# on_project_first_start: command\n\n# Run on project start, after the first time\n# on_project_restart: command\n\n# Run on project exit ( detaching from tmux session )\n# on_project_exit: command\n\n# Run on project stop\n# on_project_stop: cd liga.api.nestjs.eng && docker-compose stop postgres\n\n# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions.\n# pre_window: rbenv shell 2.0.0-p247\n\n# Pass command line options to tmux. Useful for specifying a different tmux.conf.\n# tmux_options: -f ~/.tmux.mac.conf\n\n# Change the command to call tmux.  This can be used by derivatives/wrappers like byobu.\n# tmux_command: byobu\n\n# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used.\n# startup_window: editor\n\n# Specifies (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used.\n# startup_pane: 1\n\n# Controls whether the tmux session should be attached to automatically. Defaults to true.\n# attach: false\n\nwindows:\n  - lib:\n      layout: tilled\n      # Synchronize all panes of this window, can be enabled before or after the pane commands run.\n      # 'before' represents legacy functionality and will be deprecated in a future release, in favour of 'after'\n      # synchronize: after\n      panes:\n        - npm run test:watch\n        - clear\n  - docs:\n      layout: tilled\n      # Synchronize all panes of this window, can be enabled before or after the pane commands run.\n      # 'before' represents legacy functionality and will be deprecated in a future release, in favour of 'after'\n      # synchronize: after\n      panes:\n        - cd www && npm run start\n        - cd www\n#  - api: cd backend && npm run start:debug\n#  - app: cd app && ng serve\n"
  },
  {
    "path": ".tool-versions",
    "content": "nodejs 18.18.1\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Current TS File\",\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"runtimeExecutable\": \"node\",\n      \"args\": [\"${relativeFile}\"],\n      \"runtimeArgs\": [\"--nolazy\", \"-r\", \"ts-node/register/transpile-only\"],\n      \"envFile\": \"${workspaceFolder}/.env\",\n      \"cwd\": \"${workspaceRoot}\",\n      \"internalConsoleOptions\": \"openOnSessionStart\",\n      \"skipFiles\": [\"<node_internals>/**\", \"node_modules/**\"]\n    },\n    {\n      \"name\": \"Debug Jest Tests\",\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"runtimeArgs\": [\n        \"--inspect-brk\",\n        \"${workspaceRoot}/node_modules/.bin/jest\",\n        \"--runInBand\"\n      ],\n      \"envFile\": \"${workspaceFolder}/.env\",\n      \"console\": \"integratedTerminal\",\n      \"internalConsoleOptions\": \"neverOpen\",\n      \"port\": 9229,\n      \"disableOptimisticBPs\": true,\n      \"windows\": {\n        \"program\": \"${workspaceFolder}/node_modules/jest/bin/jest\"\n      }\n    },\n    {\n      \"name\": \"Debug Jest Current File\",\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"program\": \"${workspaceFolder}/node_modules/.bin/jest\",\n      \"args\": [\"${relativeFile}\", \"--config\", \"jest.config.js\"],\n      \"console\": \"integratedTerminal\",\n      \"internalConsoleOptions\": \"neverOpen\",\n      \"port\": 9229,\n      \"disableOptimisticBPs\": true,\n      \"windows\": {\n        \"program\": \"${workspaceFolder}/node_modules/jest/bin/jest\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"editor.formatOnSave\": true,\n  \"[typescript]\": {\n    \"editor.defaultFormatter\": \"esbenp.prettier-vscode\"\n  }\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## [4.4.0](https://github.com/H4ad/serverless-adapter/compare/v4.3.2...v4.4.0) (2024-12-01)\n\n\n### Features\n\n* **express-v5:** added support to express v5 and body-parser v2 ([e435b97](https://github.com/H4ad/serverless-adapter/commit/e435b97e09783de62801374a1fb365c553ed4833))\n* **fastify-v5:** ensure support to fastify v5 ([bd09e46](https://github.com/H4ad/serverless-adapter/commit/bd09e4685a78f12851ab0f99fab19dae26c52d8d))\n* **firebase:** ensure support to v5 and v6 sdk ([bc6886e](https://github.com/H4ad/serverless-adapter/commit/bc6886eadab75c7f18e3e9c2bcc886ec3b7f714c))\n\n\n### Miscellaneous Chores\n\n* bump cross-spawn and @swc/cli in /benchmark ([0e4db68](https://github.com/H4ad/serverless-adapter/commit/0e4db6820ab0836f1e2dfbe60dc692288f0c7157))\n* bump cross-spawn from 7.0.3 to 7.0.6 in /www ([ce1d0cd](https://github.com/H4ad/serverless-adapter/commit/ce1d0cdb27133402ed624fb3fba96caed95fa905))\n* bump micromatch from 4.0.5 to 4.0.8 in /benchmark ([1ddc2a9](https://github.com/H4ad/serverless-adapter/commit/1ddc2a990f868e63d6f8c29b65e4f7a0056736f4))\n* bump webpack from 5.89.0 to 5.96.1 in /www ([47392b0](https://github.com/H4ad/serverless-adapter/commit/47392b0bbd973ad06a30e364e334444144559944))\n* **http-deepkit:** ensure is working with version 1.0.1-alpha-155 ([b1ee6d4](https://github.com/H4ad/serverless-adapter/commit/b1ee6d4beb3219b7d63350502073530c637c826b))\n* **packages:** bump lib package versions ([15bc6ad](https://github.com/H4ad/serverless-adapter/commit/15bc6ad7baae905971c04c88337c563fe65e913c))\n\n## [4.3.2](https://github.com/H4ad/serverless-adapter/compare/v4.3.1...v4.3.2) (2024-11-09)\n\n\n### Continuous Integration\n\n* **coverage:** do not fail when fail coverage & fix issue with test ([ff9702b](https://github.com/H4ad/serverless-adapter/commit/ff9702b38da650b94935481be54618a0fd765e6b))\n\n## [4.3.1](https://github.com/H4ad/serverless-adapter/compare/v4.3.0...v4.3.1) (2024-11-09)\n\n\n### Miscellaneous Chores\n\n* bump cookie and express in /www ([22d850f](https://github.com/H4ad/serverless-adapter/commit/22d850fab96240c110ee6fbc75473c8bbefd11c2))\n* bump serve-static and express in /benchmark ([249af0c](https://github.com/H4ad/serverless-adapter/commit/249af0c9d3dfa1f5fda23f8a49f720f3c96c4f07))\n* **codecov:** fix issues with upload coverage ([4b5b39e](https://github.com/H4ad/serverless-adapter/commit/4b5b39e7c54d5b37913a9d7866a626515b8c06b6))\n* **reflect-metadata:** allow more general versions for reflect metadata ([816cc51](https://github.com/H4ad/serverless-adapter/commit/816cc51afee8024907eb399ed9fe625f828c98ad))\n\n## [4.3.0](https://github.com/H4ad/serverless-adapter/compare/v4.2.3...v4.3.0) (2024-09-18)\n\n\n### Features\n\n* **aws-stream-handler:** add flag to customize callbackWaitsForEmptyEventLoop ([#264](https://github.com/H4ad/serverless-adapter/issues/264)) ([30a59f9](https://github.com/H4ad/serverless-adapter/commit/30a59f99e83cd16f5a7c37bc4296f7501f59fd36))\n\n## [4.2.3](https://github.com/H4ad/serverless-adapter/compare/v4.2.2...v4.2.3) (2024-09-09)\n\n\n### Bug Fixes\n\n* **response-stream:** improve chunk identification (fixes [#260](https://github.com/H4ad/serverless-adapter/issues/260)) ([2aa474e](https://github.com/H4ad/serverless-adapter/commit/2aa474e02c533d31b5086866a78afdedd3058f04))\n\n\n### Documentation\n\n* **response-stream:** add comments and references explaining implementation ([d39db53](https://github.com/H4ad/serverless-adapter/commit/d39db532a2ca9ebd7754dd364f88cf8bf0ed0a18))\n\n\n### Tests\n\n* **response-stream:** test eagerly flushed headers ([0f33c29](https://github.com/H4ad/serverless-adapter/commit/0f33c29e2bfc99194c61887bb908763625e357b7))\n\n## [4.2.2](https://github.com/H4ad/serverless-adapter/compare/v4.2.1...v4.2.2) (2024-09-06)\n\n\n### Bug Fixes\n\n* **apig-v1-adapter:** lowercase request headers ([4fbb588](https://github.com/H4ad/serverless-adapter/commit/4fbb5880283ba0fad54374baeb572ca706b804e6))\n\n\n### Documentation\n\n* fix Apollo Server package name in npm command ([4d4cece](https://github.com/H4ad/serverless-adapter/commit/4d4ceced9d2f882f7431830134d293c187aff4f3))\n* **getting-started:** update npm install command ([ee4661f](https://github.com/H4ad/serverless-adapter/commit/ee4661fc3a7a3d518d4ff3f4ff033ce5a01066ba))\n\n\n### Miscellaneous Chores\n\n* bump express from 4.18.2 to 4.19.2 in /benchmark ([98e84d1](https://github.com/H4ad/serverless-adapter/commit/98e84d1a6cb7d05bab6506bf2225573c8bd6e50d))\n\n## [4.2.1](https://github.com/H4ad/serverless-adapter/compare/v4.2.0...v4.2.1) (2024-02-29)\n\n\n### Bug Fixes\n\n* **response-stream:** fix response with no content doesn't correctly end the writable stream ([bded8cf](https://github.com/H4ad/serverless-adapter/commit/bded8cfe32a853529fea7334658709b12b2971e1))\n\n\n### Code Refactoring\n\n* **apollo-server-mutation:** better types for adapter ([79f3383](https://github.com/H4ad/serverless-adapter/commit/79f33833c4368282d421495b6f7a70a700bd06bb))\n* **response-stream:** avoid creating object on log while parsing headers ([1effcae](https://github.com/H4ad/serverless-adapter/commit/1effcaebf23e83188d4836693428f1953d0403be))\n\n\n### Tests\n\n* **all:** cleaning tests and fixing ts issues ([c3dcfff](https://github.com/H4ad/serverless-adapter/commit/c3dcfff58ac3bc29294337abd074c567724a8198))\n* **aws-stream:** add tests to cover [#206](https://github.com/H4ad/serverless-adapter/issues/206) ([c853149](https://github.com/H4ad/serverless-adapter/commit/c853149a6295f015b467825f20a60790cb346f65))\n\n## [4.2.0](https://github.com/H4ad/serverless-adapter/compare/v4.1.0...v4.2.0) (2024-01-08)\n\n\n### Features\n\n* **frameworks:** added support for polka ([39377cb](https://github.com/H4ad/serverless-adapter/commit/39377cb16b20bdba7b724663b8076a6a394851a6))\n\n\n### Miscellaneous Chores\n\n* bump @apollo/server from 4.9.5 to 4.10.0 ([cf4e1d9](https://github.com/H4ad/serverless-adapter/commit/cf4e1d9485fe174c68ae1b70dc2c6d6e7a220c02))\n* bump @rushstack/node-core-library from 3.62.0 to 3.63.0 ([19c88e0](https://github.com/H4ad/serverless-adapter/commit/19c88e01c74a8e4735ba66f6b5b77b2cbd579897))\n* bump @vitest/coverage-v8 from 1.1.0 to 1.1.3 ([3e67b23](https://github.com/H4ad/serverless-adapter/commit/3e67b23dba80b00c65667c312578f07d39111919))\n* bump eslint-plugin-prettier from 5.1.1 to 5.1.2 ([83fc5e5](https://github.com/H4ad/serverless-adapter/commit/83fc5e5cac5a08701815a6c73563a51866fdcbf9))\n* bump fastify from 4.25.1 to 4.25.2 ([e048b11](https://github.com/H4ad/serverless-adapter/commit/e048b117034c2f4e7f3b25467dd24fa3b754e684))\n* bump follow-redirects from 1.15.3 to 1.15.4 in /www ([af12bbd](https://github.com/H4ad/serverless-adapter/commit/af12bbd55d264dc2be668e24cb1f551e333f33ba))\n* bump koa from 2.14.2 to 2.15.0 ([164c97b](https://github.com/H4ad/serverless-adapter/commit/164c97ba10e6d0ee4661bc980d279262f4a982c1))\n* bump vite from 5.0.10 to 5.0.11 ([0478492](https://github.com/H4ad/serverless-adapter/commit/04784922a49429a57f9bbbd4773e42c069ce2cca))\n\n## [4.1.0](https://github.com/H4ad/serverless-adapter/compare/v4.0.1...v4.1.0) (2024-01-03)\n\n\n### Features\n\n* **network:** support buffering transfer-encoding: chunked ([f19ffd1](https://github.com/H4ad/serverless-adapter/commit/f19ffd1f6b2da4cccbd2be6e48429c566719ade6))\n\n## [4.0.1](https://github.com/H4ad/serverless-adapter/compare/v4.0.0...v4.0.1) (2023-12-26)\n\n\n### Bug Fixes\n\n* **ci:** missing build part while releasing new version ([5b7d184](https://github.com/H4ad/serverless-adapter/commit/5b7d18410acdc0aa547de2db63cf6347a5715b58))\n\n\n### Documentation\n\n* **blog:** added note about bug related to missing package files ([1d75d91](https://github.com/H4ad/serverless-adapter/commit/1d75d91fe8863c45ae2a7abe44aec6d51d96e44d))\n\n## [4.0.0](https://github.com/H4ad/serverless-adapter/compare/v3.2.0...v4.0.0) (2023-12-26)\n\n\n### ⚠ BREAKING CHANGES\n\n* Now we support dual package publish, and the import can fail.\n\n### Features\n\n* added support for dual package publish ([dd0803f](https://github.com/H4ad/serverless-adapter/commit/dd0803ff5ebcabf22120da88b74a720c3661f846))\n\n\n### Bug Fixes\n\n* **dual-package-publish:** issue with imports lib when moduleResolution is node ([4dac8aa](https://github.com/H4ad/serverless-adapter/commit/4dac8aa07ef015f3b0fd8f8d766705271e93c111))\n\n\n### Documentation\n\n* **blog:** added blogpost about dual package publish ([006e8a9](https://github.com/H4ad/serverless-adapter/commit/006e8a94b02152e4857cda7951e285ff2b449430))\n* updated documentation for dual package publish ([03ee217](https://github.com/H4ad/serverless-adapter/commit/03ee21746bee785d840ab26a1ec5ddf2bd6dea90))\n\n\n### Continuous Integration\n\n* **release:** fixed issue with release-please skipping release ([8dfb582](https://github.com/H4ad/serverless-adapter/commit/8dfb582742481f7e37e076f00c51d32907f401fd))\n\n## [3.2.0](https://github.com/H4ad/serverless-adapter/compare/v3.1.0...v3.2.0) (2023-12-22)\n\n\n### Features\n\n* **firebase:** bump supported firebase functions to 4.x ([b717240](https://github.com/H4ad/serverless-adapter/commit/b717240a808d7d81905745347b17969e7caaf6f5))\n\n\n### Documentation\n\n* **readme:** removed semantic release badge ([fe85304](https://github.com/H4ad/serverless-adapter/commit/fe8530439df4ed48d3542127227ae98954fd84a5))\n\n\n### Miscellaneous Chores\n\n* **benchmark:** bump package versions ([b6aa539](https://github.com/H4ad/serverless-adapter/commit/b6aa539bb499fcadd2393c7bf010dfe6d726f2d5))\n* bootstrap releases for path: . ([e68506e](https://github.com/H4ad/serverless-adapter/commit/e68506ea9c5a5fb8492b7cc7bb03400c95700668))\n* bump @apollo/server from 4.7.4 to 4.9.3 ([52c8b83](https://github.com/H4ad/serverless-adapter/commit/52c8b83db4d8b80120aea6ccb32e8b4580466168))\n* bump semver from 5.7.1 to 5.7.2 in /benchmark ([0a6a3e0](https://github.com/H4ad/serverless-adapter/commit/0a6a3e0a0e536f43e2c61f307f955b01a97e1169))\n* bump semver from 5.7.1 to 5.7.2 in /www ([49c7baf](https://github.com/H4ad/serverless-adapter/commit/49c7baf364e251d78da4349ab35c6b69837a003d))\n* bump vite from 4.3.5 to 4.4.9 ([ecd1252](https://github.com/H4ad/serverless-adapter/commit/ecd125253229ed032f21606238fbc27fc74d5e95))\n* bump vite from 4.4.9 to 5.0.10 ([8eadf40](https://github.com/H4ad/serverless-adapter/commit/8eadf405eea86facff1268b9fb4d5d153a873fbb))\n* bump word-wrap from 1.2.3 to 1.2.4 ([218d3a9](https://github.com/H4ad/serverless-adapter/commit/218d3a906c0b18156110c4c8fe155d0f183fca29))\n* **docs:** update to docusaurus v3 ([51a104e](https://github.com/H4ad/serverless-adapter/commit/51a104e000e867ae3601a70408cec8d0ab2d8cc3))\n* **package:** bump package versions ([fe0a0fc](https://github.com/H4ad/serverless-adapter/commit/fe0a0fc35c687037dfa172dbb667c4451d539ad8))\n* **release-please:** set latest version ([69110ec](https://github.com/H4ad/serverless-adapter/commit/69110ec1f418831ac4a49545d1bf40c291212293))\n* **semantic-release:** removed unused package ([2c60275](https://github.com/H4ad/serverless-adapter/commit/2c602753ecd3fcdff23567ec8a77e317ebd7f9fe))\n\n\n### Continuous Integration\n\n* **codeql:** run only when changing code files ([93d8f1c](https://github.com/H4ad/serverless-adapter/commit/93d8f1c029e2c84e5c4b1366ecddc9b1b11c6fa5))\n* **codeql:** updated configuration ([9ffa3e8](https://github.com/H4ad/serverless-adapter/commit/9ffa3e8b5f4c7df8772cd64ef8640646879f713f))\n* **docs:** only trigger when update workflows of docs ([c1e7f8a](https://github.com/H4ad/serverless-adapter/commit/c1e7f8aefdaf18a12f5a26c2b0cbc94f4c830322))\n* **pr:** only run when update specific files ([0085520](https://github.com/H4ad/serverless-adapter/commit/0085520b20edb0a33111bdb7780195805d31b0af))\n* **pr:** stop running the pr on main ([7c7a05a](https://github.com/H4ad/serverless-adapter/commit/7c7a05a78928a2ef96d67dae38f6f56b25361575))\n* **release-please:** try fix issues with release please config ([46577f2](https://github.com/H4ad/serverless-adapter/commit/46577f2c79bcc9f20b9925f6fa629f534d63a4f9))\n* **release:** added coverage ([57f1e09](https://github.com/H4ad/serverless-adapter/commit/57f1e09d63936546764708880e5dd5e799c332b6))\n* **release:** added provenance during publish ([1161e42](https://github.com/H4ad/serverless-adapter/commit/1161e4227fb63ad272ba740ba186de63d40955c3))\n* **release:** include all commits on release ([9185a0b](https://github.com/H4ad/serverless-adapter/commit/9185a0b6ab34174905669cfdd084b2cc9afe54bb))\n* **release:** moved configuration to the correct place ([b8c6156](https://github.com/H4ad/serverless-adapter/commit/b8c6156eb3d7df06f1c370965e91abc850217adc))\n* **release:** use release manager instead of merge-and-release ([ef278e6](https://github.com/H4ad/serverless-adapter/commit/ef278e6efc2732e5e21d2e3ae9d32fb96ac1edc2))\n* **workflows:** bump action versions ([647e694](https://github.com/H4ad/serverless-adapter/commit/647e694ce6919925c5df4188450e49faa5ec3fc8))\n\nCHANGES:\n\n## [3.1.0](https://github.com/H4ad/serverless-adapter/compare/v3.0.0...v3.1.0) (2023-07-01)\n\n\n### Bug Fixes\n\n* **build:** disable minify identifiers ([0a285a6](https://github.com/H4ad/serverless-adapter/commit/0a285a6b2249d56ce39a762872bcc7cfb4515f8c))\n* **package:** types not being emitted ([2bc1244](https://github.com/H4ad/serverless-adapter/commit/2bc124456f41855798ed7d5c4a132b2d83bf16fd))\n\n\n### Features\n\n* **aws:** added adapter for request lambda edge ([b8791da](https://github.com/H4ad/serverless-adapter/commit/b8791da9c4718a837d9ae01d89bba7b30067dc52))\n\n## [3.0.0](https://github.com/H4ad/serverless-adapter/compare/v2.17.0...v3.0.0) (2023-06-09)\n\n\n### Bug Fixes\n\n* **api-gateway-v1:** probably missing query string value when multiple ([78b9f18](https://github.com/H4ad/serverless-adapter/commit/78b9f18dfb8a459f0c1557fdf702f68a078c098b))\n\n\n* perf(api-gateway-v2)!: single pass when collecting headers and cookies on response ([3d65895](https://github.com/H4ad/serverless-adapter/commit/3d65895f174db00e2e45b3626223874a2d71f40a))\n* refactor(core)!: removed support for regex on binary validation and case-sensitive headers ([4fb3a39](https://github.com/H4ad/serverless-adapter/commit/4fb3a39f0434d29d66b018f451698954ecbf3ed4))\n* chore(nodejs)!: deprecate node 12.x, 14.x and 16.x ([4c734d4](https://github.com/H4ad/serverless-adapter/commit/4c734d4fed3bb9384b514ccf28d41f34c5360b76))\n\n\n### Features\n\n* **trpc:** bump support for 10.x ([5d3124a](https://github.com/H4ad/serverless-adapter/commit/5d3124a115dc44099fc681eec9592636374f85b8))\n\n\n### Performance Improvements\n\n* **api-gateway-v1:** faster getRequest ([70f7020](https://github.com/H4ad/serverless-adapter/commit/70f7020e347e57417920b32eb68d4456df7db246))\n* **api-gateway-v2:** faster getRequest method ([3b08708](https://github.com/H4ad/serverless-adapter/commit/3b087087af1873414c85c8db09b5867c0752ab56))\n* **aws:** optimized strip base path ([f72967a](https://github.com/H4ad/serverless-adapter/commit/f72967afaa1cdc4dbc95cc2298d560dc21b27884))\n* **default-handler:** always log using fn ([36950b3](https://github.com/H4ad/serverless-adapter/commit/36950b36e246a43dc45d2d9ef2d989402eef916b))\n* **headers:** use object.keys + reduce instead of entries ([41339c6](https://github.com/H4ad/serverless-adapter/commit/41339c681f52b05328097a8b4cbb9cf27e704a84))\n* **logger:** faster logger ([103817c](https://github.com/H4ad/serverless-adapter/commit/103817c7a284dabedb78807d6db7fbf2ed42ed75))\n* **optional:** use strict equal instead of typeof ([1fba12c](https://github.com/H4ad/serverless-adapter/commit/1fba12c6e22089376437a8976971ad30df1283e1))\n* **tsconfig:** do not use define because is slower ([35ce7c7](https://github.com/H4ad/serverless-adapter/commit/35ce7c738b69a39b7179f1d8cae40924967ad0cd))\n\n\n### Tests\n\n* **vitest:** replaced jest for vitest ([7505fad](https://github.com/H4ad/serverless-adapter/commit/7505fad2b3078aabbc72c105033043c597842933))\n\n\n### BREAKING CHANGES\n\n* now we don't flatten the headers\n* now regex is not support anymore due the slow performance and we don't lower case\nall the headers, so the content-encoding and content-type must be lowercase\n* **vitest:** removed support for fastify 3.0.0 & hapi 20.x & firebase-admin < 11\n* Now we will no longer support old nodejs versions\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nWhen contributing to this repository, please first discuss the change you wish to make via issue,\nemail, or any other method with the owners of this repository before making a change. \n\nPlease note we have a code of conduct, please follow it in all your interactions with the project.\n\n## Pull Request Process\n\n1. Install the dependencies with `npm ci` and then go into the `www` folder and install the dependencies again.\n2. After creating your resource or fixing a bug, verify that the tests are correct with `npm run test`.\n3. Be sure to update the documentation if you add a new feature, the docs are inside `www/docs/main`, to see your changes, run `npm run start`.\n4. Once we've reviewed and ensured that all of these things are correct, we'll merge your Pull-Request.\n\n## Code of Conduct\n\n### Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, gender identity and expression, level of experience,\nnationality, personal appearance, race, religion, or sexual identity and\norientation.\n\n### Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\nadvances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n### Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n### Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n### Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at [@vinii_joga10](https://twitter.com/vinii_joga10). All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n### Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2022 Vinícius Lourenço\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">\n  🚀 Serverless Adapter\n</h1>\n\n<p align=\"center\">\n  <a href=\"#install\">Install</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;\n  <a href=\"#usage\">Usage</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;\n  <a href=\"#support\">Support</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;\n  <a href=\"#examples\">Examples</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;\n  <a href=\"#benchmark\">Benchmark</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;\n  <a href=\"#architecture\">Architecture</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;\n  <a href=\"#credits\">Credits</a>\n</p>\n\n[![npm package][npm-img]][npm-url]\n[![Build Status][build-img]][build-url]\n[![Downloads][downloads-img]][downloads-url]\n[![Issues][issues-img]][issues-url]\n[![Code Coverage][codecov-img]][codecov-url]\n[![Commitizen Friendly][commitizen-img]][commitizen-url]\n\nRun REST APIs and other web applications using your existing Node.js application framework (NestJS, Deepkit, Express (v4 and v5), Koa, Hapi,\nFastify, tRPC and Apollo Server), on top of AWS Lambda, Azure, Digital Ocean and many other clouds.\n\nThis library was a refactored version of [@vendia/serverless-express](https://github.com/vendia/serverless-express), I\ncreate a new way to interact and extend event sources by creating contracts to abstract the integrations between each\nlibrary layer.\n\nWhy you would use this libray instead of [@vendia/serverless-express](https://github.com/vendia/serverless-express)?\n\n- Better APIs to extend library functionality.\n  - You don't need me to release a new version to integrate with the new event source, you can create an adapter and\n    just call the `addAdapter` method when building your handler.\n- All code can be extended, if you want to modify the current behavior you can.\n  - This is important because if you find a bug, you can quickly resolve it by extending the class, _and then you can\n    submit a PR to fix the bug_.\n- All code was written in Typescript.\n- Well documented, any method, class, or interface has comments to explain the behavior.\n- We have >99% coverage.\n\n# Installing\n\nTo be able to use, first install the library:\n\n```bash\nnpm i --save @h4ad/serverless-adapter\n```\n\n# Usage\n\nTo start to use, first you need to know what you need to import, let's start showing the [ServerlessAdapter](/docs/api/ServerlessAdapter).\n\n```tsx\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\n```\n\nWe need to pass to [Serverless Adapter](/docs/api/ServerlessAdapter) the instance of your api, let's look an example with:\n\n- Framework: [Express](../frameworks/express).\n- Adapters: [AWS Api Gateway V2 Adapter](../adapters/aws/api-gateway-v2).\n- Handler: [Default Handler](../handlers/default).\n- Resolver: [Promise Resolver](../resolvers/promise).\n\n```ts\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\nimport { ExpressFramework } from '@h4ad/serverless-adapter/lib/frameworks/express';\nimport { DefaultHandler } from '@h4ad/serverless-adapter/lib/handlers/default';\nimport { PromiseResolver } from '@h4ad/serverless-adapter/lib/resolvers/promise';\nimport { ApiGatewayV2Adapter } from '@h4ad/serverless-adapter/lib/adapters/aws';\n\nconst express = require('express');\n\nconst app = express();\nexport const handler = ServerlessAdapter.new(app)\n  .setFramework(new ExpressFramework())\n  .setHandler(new DefaultHandler())\n  .setResolver(new PromiseResolver())\n  .addAdapter(new ApiGatewayV2Adapter())\n  // if you need more adapters\n  // just append more `addAdapter` calls\n  .build();\n```\n\n# Documentation\n\nSee how to use this library [here](https://viniciusl.com.br/serverless-adapter/docs/category/getting-started).\n\n# Breaking Changes\n\nI will not consider updating/breaking compatibility of a NodeJS framework as a breaking change,\nbecause I had a lot of supported frameworks and if I created a major version for each one it would be a mess.\n\nSo if you want predictability, pin the version with `~` instead of `^`.\n\n# Examples\n\nYou can see some examples of how to use this library [here](https://github.com/H4ad/serverless-adapter-examples).\n\n# Benchmark\n\nSee the speed comparison between other libraries that have the same purpose in the [Benchmark Section](./benchmark).\n\n# Credits\n\nHonestly, I just refactored all the code that the @vendia team and many other contributors wrote, thanks so much to them\nfor existing and giving us a brilliant library that is the core of my current company.\n\n# Sponsors\n\n| <a href=\"https://liga.facens.br/\"><img height=\"50\" src=\"https://mlogu6g7z5ex.i.optimole.com/yEwfkqo-4R0ttNtd/w:auto/h:auto/q:mauto/f:avif/http://liga.facens.br/wp-content/uploads/2020/03/logo-1.png\" title=\"The LIGA logo\" width=\"100\"/></a> |\n|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n\n[build-img]:https://github.com/H4ad/serverless-adapter/actions/workflows/release.yml/badge.svg\n\n[build-url]:https://github.com/H4ad/serverless-adapter/actions/workflows/release.yml\n\n[downloads-img]:https://img.shields.io/npm/dt/serverless-adapter\n\n[downloads-url]:https://www.npmtrends.com/@h4ad/serverless-adapter\n\n[npm-img]:https://img.shields.io/npm/v/@h4ad/serverless-adapter\n\n[npm-url]:https://www.npmjs.com/package/@h4ad/serverless-adapter\n\n[issues-img]:https://img.shields.io/github/issues/H4ad/serverless-adapter\n\n[issues-url]:https://github.com/H4ad/serverless-adapter/issues\n\n[codecov-img]:https://codecov.io/gh/H4ad/serverless-adapter/branch/main/graph/badge.svg\n\n[codecov-url]:https://codecov.io/gh/H4ad/serverless-adapter\n\n[commitizen-img]:https://img.shields.io/badge/commitizen-friendly-brightgreen.svg\n\n[commitizen-url]:http://commitizen.github.io/cz-cli/\n"
  },
  {
    "path": "api-extractor.json",
    "content": "/**\n * Config file for API Extractor.  For more info, please visit: https://api-extractor.com\n */\n{\n  \"$schema\": \"https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json\",\n  /**\n   * Optionally specifies another JSON config file that this file extends from.  This provides a way for\n   * standard settings to be shared across multiple projects.\n   *\n   * If the path starts with \"./\" or \"../\", the path is resolved relative to the folder of the file that contains\n   * the \"extends\" field.  Otherwise, the first path segment is interpreted as an NPM package name, and will be\n   * resolved using NodeJS require().\n   *\n   * SUPPORTED TOKENS: none\n   * DEFAULT VALUE: \"\"\n   */\n  // \"extends\": \"./shared/api-extractor-base.json\"\n  // \"extends\": \"my-package/include/api-extractor-base.json\"\n\n  /**\n   * Determines the \"<projectFolder>\" token that can be used with other config file settings.  The project folder\n   * typically contains the tsconfig.json and package.json config files, but the path is user-defined.\n   *\n   * The path is resolved relative to the folder of the config file that contains the setting.\n   *\n   * The default value for \"projectFolder\" is the token \"<lookup>\", which means the folder is determined by traversing\n   * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder\n   * that contains a tsconfig.json file.  If a tsconfig.json file cannot be found in this way, then an error\n   * will be reported.\n   *\n   * SUPPORTED TOKENS: <lookup>\n   * DEFAULT VALUE: \"<lookup>\"\n   */\n  // \"projectFolder\": \"..\",\n\n  /**\n   * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis.  API Extractor\n   * analyzes the symbols exported by this module.\n   *\n   * The file extension must be \".d.ts\" and not \".ts\".\n   *\n   * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n   * prepend a folder token such as \"<projectFolder>\".\n   *\n   * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n   */\n  \"mainEntryPointFilePath\": \"<projectFolder>/lib/index.doc.d.ts\",\n  /**\n   * A list of NPM package names whose exports should be treated as part of this package.\n   *\n   * For example, suppose that Webpack is used to generate a distributed bundle for the project \"library1\",\n   * and another NPM package \"library2\" is embedded in this bundle.  Some types from library2 may become part\n   * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly\n   * imports library2.  To avoid this, we can specify:\n   *\n   *   \"bundledPackages\": [ \"library2\" ],\n   *\n   * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been\n   * local files for library1.\n   */\n  \"bundledPackages\": [],\n  /**\n   * Determines how the TypeScript compiler engine will be invoked by API Extractor.\n   */\n  \"compiler\": {\n    /**\n     * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.\n     *\n     * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n     * prepend a folder token such as \"<projectFolder>\".\n     *\n     * Note: This setting will be ignored if \"overrideTsconfig\" is used.\n     *\n     * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n     * DEFAULT VALUE: \"<projectFolder>/tsconfig.json\"\n     */\n    // \"tsconfigFilePath\": \"<projectFolder>/tsconfig.json\",\n    /**\n     * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.\n     * The object must conform to the TypeScript tsconfig schema:\n     *\n     * http://json.schemastore.org/tsconfig\n     *\n     * If omitted, then the tsconfig.json file will be read from the \"projectFolder\".\n     *\n     * DEFAULT VALUE: no overrideTsconfig section\n     */\n    // \"overrideTsconfig\": {\n    //   . . .\n    // }\n    /**\n     * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended\n     * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when\n     * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses\n     * for its analysis.  Where possible, the underlying issue should be fixed rather than relying on skipLibCheck.\n     *\n     * DEFAULT VALUE: false\n     */\n    // \"skipLibCheck\": true,\n  },\n  /**\n   * Configures how the API report file (*.api.md) will be generated.\n   */\n  \"apiReport\": {\n    /**\n     * (REQUIRED) Whether to generate an API report.\n     */\n    \"enabled\": true\n\n    /**\n     * The filename for the API report files.  It will be combined with \"reportFolder\" or \"reportTempFolder\" to produce\n     * a full file path.\n     *\n     * The file extension should be \".api.md\", and the string should not contain a path separator such as \"\\\" or \"/\".\n     *\n     * SUPPORTED TOKENS: <packageName>, <unscopedPackageName>\n     * DEFAULT VALUE: \"<unscopedPackageName>.api.md\"\n     */\n    // \"reportFileName\": \"<unscopedPackageName>.api.md\",\n\n    /**\n     * Specifies the folder where the API report file is written.  The file name portion is determined by\n     * the \"reportFileName\" setting.\n     *\n     * The API report file is normally tracked by Git.  Changes to it can be used to trigger a branch policy,\n     * e.g. for an API review.\n     *\n     * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n     * prepend a folder token such as \"<projectFolder>\".\n     *\n     * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n     * DEFAULT VALUE: \"<projectFolder>/etc/\"\n     */\n    // \"reportFolder\": \"<projectFolder>/etc/\",\n\n    /**\n     * Specifies the folder where the temporary report file is written.  The file name portion is determined by\n     * the \"reportFileName\" setting.\n     *\n     * After the temporary file is written to disk, it is compared with the file in the \"reportFolder\".\n     * If they are different, a production build will fail.\n     *\n     * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n     * prepend a folder token such as \"<projectFolder>\".\n     *\n     * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n     * DEFAULT VALUE: \"<projectFolder>/temp/\"\n     */\n    // \"reportTempFolder\": \"<projectFolder>/temp/\"\n  },\n  /**\n   * Configures how the doc model file (*.api.json) will be generated.\n   */\n  \"docModel\": {\n    /**\n     * (REQUIRED) Whether to generate a doc model file.\n     */\n    \"enabled\": true\n\n    /**\n     * The output path for the doc model file.  The file extension should be \".api.json\".\n     *\n     * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n     * prepend a folder token such as \"<projectFolder>\".\n     *\n     * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n     * DEFAULT VALUE: \"<projectFolder>/temp/<unscopedPackageName>.api.json\"\n     */\n    // \"apiJsonFilePath\": \"<projectFolder>/temp/<unscopedPackageName>.api.json\"\n  },\n  /**\n   * Configures how the .d.ts rollup file will be generated.\n   */\n  \"dtsRollup\": {\n    /**\n     * (REQUIRED) Whether to generate the .d.ts rollup file.\n     */\n    \"enabled\": true\n\n    /**\n     * Specifies the output path for a .d.ts rollup file to be generated without any trimming.\n     * This file will include all declarations that are exported by the main entry point.\n     *\n     * If the path is an empty string, then this file will not be written.\n     *\n     * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n     * prepend a folder token such as \"<projectFolder>\".\n     *\n     * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n     * DEFAULT VALUE: \"<projectFolder>/dist/<unscopedPackageName>.d.ts\"\n     */\n    // \"untrimmedFilePath\": \"<projectFolder>/dist/<unscopedPackageName>.d.ts\",\n\n    /**\n     * Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"beta\" release.\n     * This file will include only declarations that are marked as \"@public\" or \"@beta\".\n     *\n     * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n     * prepend a folder token such as \"<projectFolder>\".\n     *\n     * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n     * DEFAULT VALUE: \"\"\n     */\n    // \"betaTrimmedFilePath\": \"<projectFolder>/dist/<unscopedPackageName>-beta.d.ts\",\n\n    /**\n     * Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"public\" release.\n     * This file will include only declarations that are marked as \"@public\".\n     *\n     * If the path is an empty string, then this file will not be written.\n     *\n     * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n     * prepend a folder token such as \"<projectFolder>\".\n     *\n     * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n     * DEFAULT VALUE: \"\"\n     */\n    // \"publicTrimmedFilePath\": \"<projectFolder>/dist/<unscopedPackageName>-public.d.ts\",\n\n    /**\n     * When a declaration is trimmed, by default it will be replaced by a code comment such as\n     * \"Excluded from this release type: exampleMember\".  Set \"omitTrimmingComments\" to true to remove the\n     * declaration completely.\n     *\n     * DEFAULT VALUE: false\n     */\n    // \"omitTrimmingComments\": true\n  },\n  /**\n   * Configures how the tsdoc-metadata.json file will be generated.\n   */\n  \"tsdocMetadata\": {\n    /**\n     * Whether to generate the tsdoc-metadata.json file.\n     *\n     * DEFAULT VALUE: true\n     */\n    // \"enabled\": true,\n    /**\n     * Specifies where the TSDoc metadata file should be written.\n     *\n     * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n     * prepend a folder token such as \"<projectFolder>\".\n     *\n     * The default value is \"<lookup>\", which causes the path to be automatically inferred from the \"tsdocMetadata\",\n     * \"typings\" or \"main\" fields of the project's package.json.  If none of these fields are set, the lookup\n     * falls back to \"tsdoc-metadata.json\" in the package folder.\n     *\n     * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n     * DEFAULT VALUE: \"<lookup>\"\n     */\n    // \"tsdocMetadataFilePath\": \"<projectFolder>/dist/tsdoc-metadata.json\"\n  },\n  /**\n   * Specifies what type of newlines API Extractor should use when writing output files.  By default, the output files\n   * will be written with Windows-style newlines.  To use POSIX-style newlines, specify \"lf\" instead.\n   * To use the OS's default newline kind, specify \"os\".\n   *\n   * DEFAULT VALUE: \"crlf\"\n   */\n  // \"newlineKind\": \"crlf\",\n\n  /**\n   * Configures how API Extractor reports error and warning messages produced during analysis.\n   *\n   * There are three sources of messages:  compiler messages, API Extractor messages, and TSDoc messages.\n   */\n  \"messages\": {\n    /**\n     * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing\n     * the input .d.ts files.\n     *\n     * TypeScript message identifiers start with \"TS\" followed by an integer.  For example: \"TS2551\"\n     *\n     * DEFAULT VALUE:  A single \"default\" entry with logLevel=warning.\n     */\n    \"compilerMessageReporting\": {\n      /**\n       * Configures the default routing for messages that don't match an explicit rule in this table.\n       */\n      \"default\": {\n        /**\n         * Specifies whether the message should be written to the the tool's output log.  Note that\n         * the \"addToApiReportFile\" property may supersede this option.\n         *\n         * Possible values: \"error\", \"warning\", \"none\"\n         *\n         * Errors cause the build to fail and return a nonzero exit code.  Warnings cause a production build fail\n         * and return a nonzero exit code.  For a non-production build (e.g. when \"api-extractor run\" includes\n         * the \"--local\" option), the warning is displayed but the build will not fail.\n         *\n         * DEFAULT VALUE: \"warning\"\n         */\n        \"logLevel\": \"warning\"\n\n        /**\n         * When addToApiReportFile is true:  If API Extractor is configured to write an API report file (.api.md),\n         * then the message will be written inside that file; otherwise, the message is instead logged according to\n         * the \"logLevel\" option.\n         *\n         * DEFAULT VALUE: false\n         */\n        // \"addToApiReportFile\": false\n      }\n\n      // \"TS2551\": {\n      //   \"logLevel\": \"warning\",\n      //   \"addToApiReportFile\": true\n      // },\n      //\n      // . . .\n    },\n    /**\n     * Configures handling of messages reported by API Extractor during its analysis.\n     *\n     * API Extractor message identifiers start with \"ae-\".  For example: \"ae-extra-release-tag\"\n     *\n     * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings\n     */\n    \"extractorMessageReporting\": {\n      \"default\": {\n        \"logLevel\": \"warning\"\n        // \"addToApiReportFile\": false\n      }\n\n      // \"ae-extra-release-tag\": {\n      //   \"logLevel\": \"warning\",\n      //   \"addToApiReportFile\": true\n      // },\n      //\n      // . . .\n    },\n    /**\n     * Configures handling of messages reported by the TSDoc parser when analyzing code comments.\n     *\n     * TSDoc message identifiers start with \"tsdoc-\".  For example: \"tsdoc-link-tag-unescaped-text\"\n     *\n     * DEFAULT VALUE:  A single \"default\" entry with logLevel=warning.\n     */\n    \"tsdocMessageReporting\": {\n      \"default\": {\n        \"logLevel\": \"warning\"\n        // \"addToApiReportFile\": false\n      }\n\n      // \"tsdoc-link-tag-unescaped-text\": {\n      //   \"logLevel\": \"warning\",\n      //   \"addToApiReportFile\": true\n      // },\n      //\n      // . . .\n    }\n  }\n}\n"
  },
  {
    "path": "benchmark/.gitignore",
    "content": "node_modules\n*.cpuprofile\n.clinic\n"
  },
  {
    "path": "benchmark/.swcrc",
    "content": "{\n  \"env\": {\n    \"targets\": \"node >= 18\"\n  },\n  \"module\": {\n    \"type\": \"commonjs\",\n    \"strict\": true,\n  },\n  \"jsc\": {\n    \"target\": \"es2022\",\n    \"parser\": {\n      \"syntax\": \"typescript\",\n      \"tsx\": false,\n      \"dynamicImport\": true\n    }\n  }\n}\n"
  },
  {
    "path": "benchmark/README.md",
    "content": "# Benchmark\n\nIn this folder, we have benchmarks to compare the speed of this library with others.\n\n## How to Run\n\n```bash\ngit clone git@github.com:H4ad/serverless-adapter.git\ncd serverless-adapter\nnpm ci\nnpm run build\nnpm pack\ncd benchmark\nnpm ci\nnpm i ../h4ad-serverless-adapter-0.0.0-development.tgz\nnpm run bench\n```\n\n## Latest Run\n\n- CPU: Ryzen 2200g\n- Memory: 32GB 3200Hz\n\n```md\n@h4ad/serverless-adapter x 46,463 ops/sec ±10.75% (65 runs sampled)\n@vendia/serverless-express x 8,726 ops/sec ±18.64% (82 runs sampled)\nserverless-http x 48,246 ops/sec ±8.00% (70 runs sampled)\nFastest is serverless-http,@h4ad/serverless-adapter\n```\n"
  },
  {
    "path": "benchmark/package.json",
    "content": "{\n  \"name\": \"benchmark\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"build\": \"swc src --out-dir dist\",\n    \"bench\": \"npm run build && node dist/samples/compare-libraries.js\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/H4ad/serverless-adapter.git\"\n  },\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"Vinícius Lourenço\",\n    \"email\": \"H4ad@users.noreply.github.com\",\n    \"url\": \"https://github.com/H4ad\"\n  },\n  \"dependencies\": {\n    \"@h4ad/serverless-adapter\": \"file:../h4ad-serverless-adapter-0.0.0-development.tgz\",\n    \"@swc/cli\": \"0.5.1\",\n    \"@swc/core\": \"1.3.101\",\n    \"@vendia/serverless-express\": \"4.12.6\",\n    \"benchmark\": \"2.1.4\",\n    \"express\": \"4.21.1\",\n    \"serverless-http\": \"3.2.0\",\n    \"stream-mock\": \"2.0.5\"\n  },\n  \"devDependencies\": {\n    \"@types/benchmark\": \"2.1.5\",\n    \"aws-lambda\": \"1.0.7\",\n    \"chokidar\": \"3.5.3\",\n    \"ts-node\": \"10.9.2\",\n    \"typescript\": \"5.3.3\"\n  }\n}\n"
  },
  {
    "path": "benchmark/src/events.ts",
    "content": "import { getMultiValueHeadersMap } from '@h4ad/serverless-adapter';\nimport type {\n  APIGatewayProxyEvent,\n  APIGatewayProxyEventQueryStringParameters,\n} from 'aws-lambda/trigger/api-gateway-proxy';\n\nexport function createApiGatewayV1(\n  httpMethod: string,\n  path: string,\n  body?: Record<string, unknown>,\n  headers?: Record<string, string>,\n  queryParams?: APIGatewayProxyEventQueryStringParameters,\n): APIGatewayProxyEvent {\n  return {\n    resource: '/{proxy+}',\n    path,\n    httpMethod,\n    headers: {\n      Accept: '*/*',\n      'Accept-Encoding': 'gzip, deflate, br',\n      'Accept-Language': 'en-US,en;q=0.9',\n      'cache-control': 'no-cache',\n      'CloudFront-Forwarded-Proto': 'https',\n      'CloudFront-Is-Desktop-Viewer': 'true',\n      'CloudFront-Is-Mobile-Viewer': 'false',\n      'CloudFront-Is-SmartTV-Viewer': 'false',\n      'CloudFront-Is-Tablet-Viewer': 'false',\n      'CloudFront-Viewer-Country': 'US',\n      'content-type': '',\n      Host: 'xxxxxx.execute-api.us-east-1.amazonaws.com',\n      origin: 'https://xxxxxx.execute-api.us-east-1.amazonaws.com',\n      pragma: 'no-cache',\n      Referer: 'https://xxxxxx.execute-api.us-east-1.amazonaws.com/prod/',\n      'User-Agent':\n        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36',\n      Via: '2.0 00f0a41f749793b9dd653153037c957e.cloudfront.net (CloudFront)',\n      'X-Amz-Cf-Id': '2D5N65SYHJdnJfEmAV_hC0Mw3QvkbUXDumJKAL786IGHRdq_MggPtA==',\n      'X-Amzn-Trace-Id': 'Root=1-5cdf30d0-31a428004abe13807f9445b0',\n      'X-Forwarded-For': '11.111.111.111, 11.111.111.111',\n      'X-Forwarded-Port': '443',\n      'X-Forwarded-Proto': 'https',\n      ...headers,\n    },\n    multiValueHeaders: {\n      Accept: ['*/*'],\n      'Accept-Encoding': ['gzip, deflate, br'],\n      'Accept-Language': ['en-US,en;q=0.9'],\n      'cache-control': ['no-cache'],\n      'CloudFront-Forwarded-Proto': ['https'],\n      'CloudFront-Is-Desktop-Viewer': ['true'],\n      'CloudFront-Is-Mobile-Viewer': ['false'],\n      'CloudFront-Is-SmartTV-Viewer': ['false'],\n      'CloudFront-Is-Tablet-Viewer': ['false'],\n      'CloudFront-Viewer-Country': ['US'],\n      'content-type': [],\n      Host: ['xxxxxx.execute-api.us-east-1.amazonaws.com'],\n      origin: ['https://xxxxxx.execute-api.us-east-1.amazonaws.com'],\n      pragma: ['no-cache'],\n      Referer: ['https://xxxxxx.execute-api.us-east-1.amazonaws.com/prod/'],\n      'User-Agent': [\n        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36',\n      ],\n      Via: ['2.0 00f0a41f749793b9dd653153037c957e.cloudfront.net (CloudFront)'],\n      'X-Amz-Cf-Id': [\n        '2D5N65SYHJdnJfEmAV_hC0Mw3QvkbUXDumJKAL786IGHRdq_MggPtA==',\n      ],\n      'X-Amzn-Trace-Id': ['Root=1-5cdf30d0-31a428004abe13807f9445b0'],\n      'X-Forwarded-For': ['11.111.111.111, 11.111.111.111'],\n      'X-Forwarded-Port': ['443'],\n      'X-Forwarded-Proto': ['https'],\n      ...(headers && getMultiValueHeadersMap(headers)),\n    },\n    queryStringParameters: queryParams || null,\n    multiValueQueryStringParameters:\n      (queryParams && getMultiValueHeadersMap(queryParams)) || null,\n    pathParameters: {\n      path: path.replace(/^\\//, ''),\n    },\n    stageVariables: {},\n    requestContext: {\n      authorizer: {\n        claims: null,\n        scopes: null,\n      },\n      resourceId: 'xxxxx',\n      resourcePath: '/{proxy+}',\n      httpMethod: 'POST',\n      extendedRequestId: 'Z2SQlEORIAMFjpA=',\n      requestTime: '17/May/2019:22:08:16 +0000',\n      path,\n      accountId: 'xxxxxxxx',\n      protocol: 'HTTP/1.1',\n      stage: 'prod',\n      domainPrefix: 'xxxxxx',\n      requestTimeEpoch: 1558130896565,\n      requestId: '4589cf16-78f0-11e9-9c65-816a9b037cec',\n      identity: {\n        apiKey: null,\n        apiKeyId: null,\n        clientCert: null,\n        cognitoIdentityPoolId: null,\n        accountId: null,\n        cognitoIdentityId: null,\n        caller: null,\n        sourceIp: '11.111.111.111',\n        principalOrgId: null,\n        accessKey: null,\n        cognitoAuthenticationType: null,\n        cognitoAuthenticationProvider: null,\n        userArn: null,\n        userAgent:\n          'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36',\n        user: null,\n      },\n      domainName: 'xxxxxx.execute-api.us-east-1.amazonaws.com',\n      apiId: 'xxxxxx',\n    },\n    body: (body && JSON.stringify(body)) || null,\n    isBase64Encoded: false,\n  };\n}\n"
  },
  {
    "path": "benchmark/src/framework.mock.ts",
    "content": "import { FrameworkContract } from '@h4ad/serverless-adapter';\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport { ObjectReadableMock } from 'stream-mock';\n\n/**\n * The class that represents a mock for framework that forward the request body to the response.\n *\n * @internal\n */\nexport class FrameworkMock implements FrameworkContract<null> {\n  //#region Constructor\n\n  /**\n   * Construtor padrão\n   */\n  constructor(\n    protected readonly statusCode: number,\n    protected readonly mockedResponseData: object,\n  ) {}\n\n  //#endregion\n\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest(\n    _: null,\n    __: IncomingMessage,\n    response: ServerResponse,\n  ): void {\n    const writableOutput = new ObjectReadableMock(\n      [Buffer.from(JSON.stringify(this.mockedResponseData))],\n      {\n        objectMode: true,\n      },\n    );\n\n    response.statusCode = this.statusCode;\n    response.setHeader('content-type', 'application/json');\n\n    writableOutput.pipe(response);\n  }\n}\n"
  },
  {
    "path": "benchmark/src/samples/clone-headers.ts",
    "content": "import benchmark from 'benchmark';\nimport { createApiGatewayV1 } from '../events';\n\nconst eventV1ApiGateway = createApiGatewayV1('GET', '/test');\n\nconst randomTest = [\n  createApiGatewayV1('GET', '/pat2'),\n  createApiGatewayV1('GET', '/pat3'),\n];\nconst headers = createApiGatewayV1('GET', '/pat2').headers;\nconst suite = new benchmark.Suite();\n\nsuite.add('{...}', () => {\n  const result = { ...headers };\n});\nsuite.add('structuredClone', () =>\n  structuredClone(headers),\n);\nsuite.add('JSON.parse + JSON.stringify', () =>\n  JSON.parse(JSON.stringify(headers)),\n);\nsuite.add('for loop + object.keys', () => {\n  const headers = {};\n\n  for (const key of Object.keys([Math.floor(Math.random() * 2)]))\n    headers[key] = headers[key];\n});\n\nsuite\n  .on('cycle', function (event) {\n    console.log(String(event.target));\n  })\n  .on('complete', function () {\n    console.log('Fastest is ' + this.filter('fastest').map('name'));\n  })\n  .run({\n    async: false,\n  });\n"
  },
  {
    "path": "benchmark/src/samples/compare-libraries.ts",
    "content": "import { ServerlessAdapter } from '@h4ad/serverless-adapter/lib';\nimport { ApiGatewayV1Adapter } from '@h4ad/serverless-adapter/lib/adapters/aws';\nimport { DefaultHandler } from '@h4ad/serverless-adapter/lib/handlers/default';\nimport { PromiseResolver } from '@h4ad/serverless-adapter/lib/resolvers/promise';\nimport vendia from '@vendia/serverless-express';\nimport benchmark from 'benchmark';\nimport serverlessHttp from 'serverless-http';\nimport { createApiGatewayV1 } from '../events';\nimport { FrameworkMock } from '../framework.mock';\n\nconsole.log('Running simply-forward.ts');\n\nconst framework = new FrameworkMock(200, { message: 'Hello world' });\nconst handler = ServerlessAdapter.new(null)\n  .setHandler(new DefaultHandler())\n  .setResolver(new PromiseResolver())\n  .setFramework(framework)\n  .addAdapter(new ApiGatewayV1Adapter())\n  .build();\n\nconst falseApp = (req, res) => framework.sendRequest(null, req, res);\nconst vendiaHandler = vendia({\n  app: falseApp,\n});\n\nconst serverlessHttpHandler = serverlessHttp(falseApp);\n\nconst context = {} as any;\nconst callback = {} as any;\n\nconst eventV1ApiGateway = createApiGatewayV1('GET', '/test');\n\nconst suite = new benchmark.Suite();\n\nsuite.add(\n  '@h4ad/serverless-adapter',\n  async () => await handler(eventV1ApiGateway, context, callback),\n);\nsuite.add(\n  '@vendia/serverless-express',\n  async () => await vendiaHandler(eventV1ApiGateway, context, callback),\n);\nsuite.add(\n  'serverless-http',\n  async () => await serverlessHttpHandler(eventV1ApiGateway, context),\n);\n\nsuite\n  .on('cycle', function (event) {\n    console.log(String(event.target));\n  })\n  .on('complete', function () {\n    console.log('Fastest is ' + this.filter('fastest').map('name'));\n  })\n  .run({\n    async: false,\n  });\n"
  },
  {
    "path": "benchmark/src/samples/format-headers.ts",
    "content": "import benchmark from 'benchmark';\nimport { BothValueHeaders } from '../../../src';\nimport { createApiGatewayV1 } from '../events';\n\nfunction getFlattenedHeadersMap(\n  headersMap: BothValueHeaders,\n  separator: string = ',',\n  lowerCaseKey: boolean = false,\n): Record<string, string> {\n  const commaDelimitedHeaders: Record<string, string> = {};\n  const headersMapEntries = Object.entries(headersMap);\n\n  for (const [headerKey, headerValue] of headersMapEntries) {\n    const newKey = lowerCaseKey ? headerKey.toLowerCase() : headerKey;\n\n    if (Array.isArray(headerValue))\n      commaDelimitedHeaders[newKey] = headerValue.join(separator);\n    else commaDelimitedHeaders[newKey] = String(headerValue ?? '');\n  }\n\n  return commaDelimitedHeaders;\n}\n\nfunction getFlattenedHeadersV2(\n  headersMap: BothValueHeaders,\n  separator: string = ',',\n  lowerCaseKey: boolean = false,\n): Record<string, string> {\n  const commaDelimitedHeaders: Record<string, string> = {};\n\n  for (const [headerKey, headerValue] of Object.entries(headersMap)) {\n    const newKey = lowerCaseKey ? headerKey.toLowerCase() : headerKey;\n\n    if (Array.isArray(headerValue))\n      commaDelimitedHeaders[newKey] = headerValue.join(separator);\n    else commaDelimitedHeaders[newKey] = (headerValue ?? '') + '';\n  }\n\n  return commaDelimitedHeaders;\n}\n\nfunction getFlattenedHeadersV3(\n  headersMap: BothValueHeaders,\n  separator: string = ',',\n  lowerCaseKey: boolean = false,\n): Record<string, string> {\n  return Object.keys(headersMap).reduce((acc, headerKey) => {\n    const newKey = lowerCaseKey ? headerKey.toLowerCase() : headerKey;\n    const headerValue = headersMap[headerKey];\n\n    if (Array.isArray(headerValue)) acc[newKey] = headerValue.join(separator);\n    else acc[newKey] = (headerValue ?? '') + '';\n\n    return acc;\n  }, {});\n}\n\nconst eventV1ApiGateway = createApiGatewayV1('GET', '/test');\n\nconst suite = new benchmark.Suite();\n\nsuite.add('getFlattenedHeadersMap', () =>\n  getFlattenedHeadersMap(eventV1ApiGateway.headers),\n);\nsuite.add('getFlattenedHeadersV2', () =>\n  getFlattenedHeadersV2(eventV1ApiGateway.headers),\n);\nsuite.add('getFlattenedHeadersV3', () =>\n  getFlattenedHeadersV3(eventV1ApiGateway.headers),\n);\n\nsuite\n  .on('cycle', function (event) {\n    console.log(String(event.target));\n  })\n  .on('complete', function () {\n    console.log('Fastest is ' + this.filter('fastest').map('name'));\n  })\n  .run({\n    async: false,\n  });\n"
  },
  {
    "path": "benchmark/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"jsx\": \"preserve\",\n    \"declaration\": true,\n    \"outDir\": \"dist\",\n    \"allowJs\": false,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"noImplicitAny\": false,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"strictNullChecks\": true,\n    \"useUnknownInCatchVariables\": false\n  },\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"ts-node\": {\n    \"esm\": true\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@h4ad/serverless-adapter\",\n  \"version\": \"4.4.0\",\n  \"description\": \"Run REST APIs and other web applications using your existing Node.js application framework (NestJS, Express, Koa, Hapi, Fastify and many others), on top of AWS, Azure, Digital Ocean and many other clouds.\",\n  \"type\": \"module\",\n  \"main\": \"./lib/index.cjs\",\n  \"module\": \"./lib/index.mjs\",\n  \"types\": \"./lib/index.d.ts\",\n  \"files\": [\n    \"lib/**/*\"\n  ],\n  \"scripts\": {\n    \"prepare\": \"husky install\",\n    \"build\": \"tsup\",\n    \"build:docs\": \"tsc -p tsconfig.doc.json\",\n    \"clean\": \"rm -rf ./lib/\",\n    \"cm\": \"cz\",\n    \"lint\": \"eslint ./src/ ./test/  --fix\",\n    \"docs:generate\": \"npm run docs:generate:parsing && npm run docs:generate:markdown && npm run docs:generate:api-pages\",\n    \"docs:generate:parsing\": \"npm run build:docs && npx tsx scripts/parse-docs.ts\",\n    \"docs:generate:markdown\": \"npx tsx ./scripts/generate-markdown.ts\",\n    \"docs:generate:api-pages\": \"npx tsx ./scripts/generate-api-pages.ts\",\n    \"test:watch\": \"vitest --watch\",\n    \"test\": \"vitest --run --coverage\",\n    \"typecheck\": \"tsc --noEmit\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/H4ad/serverless-adapter.git\"\n  },\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"Vinícius Lourenço\",\n    \"email\": \"H4ad@users.noreply.github.com\",\n    \"url\": \"https://github.com/H4ad\"\n  },\n  \"engines\": {\n    \"node\": \">=18.0.0\"\n  },\n  \"keywords\": [\n    \"aws\",\n    \"serverless\",\n    \"api gateway\",\n    \"sqs\",\n    \"sns\",\n    \"lambda edge\",\n    \"alb\",\n    \"lambda\",\n    \"lambda streaming\",\n    \"response streaming\",\n    \"apollo server\",\n    \"express\",\n    \"koa\",\n    \"hapi\",\n    \"fastify\",\n    \"node.js\",\n    \"http\",\n    \"huawei\",\n    \"functiongraph\",\n    \"trpc\",\n    \"azure\",\n    \"azure functions\",\n    \"http trigger v4\",\n    \"firebase\",\n    \"firebase functions\",\n    \"firebase http events\",\n    \"deepkit\",\n    \"deepkit http\",\n    \"digital ocean\",\n    \"digital ocean functions\",\n    \"digital ocean serverless\",\n    \"gcp\",\n    \"google cloud functions\",\n    \"polka\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/H4ad/serverless-adapter/issues\"\n  },\n  \"homepage\": \"https://github.com/H4ad/serverless-adapter#readme\",\n  \"devDependencies\": {\n    \"@apollo/server\": \"4.10.0\",\n    \"@azure/functions\": \"3.5.1\",\n    \"@deepkit/app\": \"1.0.1-alpha.155\",\n    \"@deepkit/core\": \"1.0.1-alpha.154\",\n    \"@deepkit/framework\": \"1.0.1-alpha.155\",\n    \"@deepkit/http\": \"1.0.1-alpha.155\",\n    \"@deepkit/injector\": \"1.0.1-alpha.155\",\n    \"@deepkit/logger\": \"1.0.1-alpha.155\",\n    \"@deepkit/stopwatch\": \"1.0.1-alpha.155\",\n    \"@deepkit/type\": \"1.0.1-alpha.155\",\n    \"@deepkit/workflow\": \"1.0.1-alpha.155\",\n    \"@google-cloud/functions-framework\": \"3.4.2\",\n    \"@hapi/hapi\": \"21.3.2\",\n    \"@microsoft/api-documenter\": \"7.26.0\",\n    \"@microsoft/api-extractor\": \"7.48.0\",\n    \"@microsoft/api-extractor-model\": \"7.30.0\",\n    \"@microsoft/tsdoc\": \"0.15.1\",\n    \"@rushstack/node-core-library\": \"5.10.0\",\n    \"@trpc/server\": \"10.45.2\",\n    \"@types/aws-lambda\": \"8.10.146\",\n    \"@types/body-parser\": \"1.19.5\",\n    \"@types/cors\": \"2.8.17\",\n    \"@types/express\": \"4.17.21\",\n    \"@types/koa\": \"2.15.0\",\n    \"@types/node\": \"18.19.67\",\n    \"@types/polka\": \"0.5.7\",\n    \"@types/supertest\": \"6.0.2\",\n    \"@typescript-eslint/eslint-plugin\": \"6.21.0\",\n    \"@typescript-eslint/parser\": \"6.21.0\",\n    \"@vitest/coverage-v8\": \"2.1.6\",\n    \"body-parser\": \"1.20.3\",\n    \"body-parser-v2\": \"npm:body-parser@2\",\n    \"commitizen\": \"4.3.0\",\n    \"cors\": \"2.8.5\",\n    \"cz-conventional-changelog\": \"3.3.0\",\n    \"esbuild\": \"0.24.0\",\n    \"eslint\": \"8.57.1\",\n    \"eslint-config-prettier\": \"9.1.0\",\n    \"eslint-plugin-import\": \"2.31.0\",\n    \"eslint-plugin-node\": \"11.1.0\",\n    \"eslint-plugin-prettier\": \"5.2.1\",\n    \"eslint-plugin-tsdoc\": \"0.4.0\",\n    \"express\": \"4.21.1\",\n    \"express-v5\": \"npm:express@5\",\n    \"fastify\": \"4.28.1\",\n    \"fastify-v5\": \"npm:fastify@5\",\n    \"firebase-admin\": \"11.11.1\",\n    \"firebase-functions\": \"4.5.0\",\n    \"firebase-functions-v5\": \"npm:firebase-functions@5\",\n    \"firebase-functions-v6\": \"npm:firebase-functions@6\",\n    \"glob\": \"10.4.5\",\n    \"husky\": \"8.0.3\",\n    \"koa\": \"2.15.3\",\n    \"polka\": \"0.5.2\",\n    \"prettier\": \"3.4.1\",\n    \"stream-mock\": \"2.0.5\",\n    \"supertest\": \"6.3.4\",\n    \"ts-node\": \"10.9.2\",\n    \"tsup\": \"8.3.5\",\n    \"typedoc\": \"0.27.2\",\n    \"typescript\": \"~5.3.3\",\n    \"vite\": \"6.0.1\",\n    \"vitest\": \"2.1.6\"\n  },\n  \"peerDependencies\": {\n    \"@apollo/server\": \">= 4.0.0\",\n    \"@azure/functions\": \">= 2.0.0\",\n    \"@deepkit/http\": \">= 1.0.1-alpha.94\",\n    \"@google-cloud/functions-framework\": \">= 3.0.0\",\n    \"@hapi/hapi\": \">= 21.0.0\",\n    \"@trpc/server\": \">= 10.0.0\",\n    \"@types/aws-lambda\": \">= 8.10.92\",\n    \"@types/body-parser\": \">= 1.19.2\",\n    \"@types/cors\": \">= 2.8.12\",\n    \"@types/express\": \">= 4.15.4\",\n    \"@types/koa\": \">= 2.11.2\",\n    \"body-parser\": \">= 1.20.0\",\n    \"cors\": \">= 2.8.5\",\n    \"express\": \">= 4.15.4\",\n    \"fastify\": \">= 4.0.0\",\n    \"firebase-admin\": \">= 11.0.0\",\n    \"firebase-functions\": \">= 4.0.0\",\n    \"http-errors\": \">= 2.0.0\",\n    \"koa\": \">= 2.5.1\",\n    \"reflect-metadata\": \">= 0.1.13\"\n  },\n  \"peerDependenciesMeta\": {\n    \"@apollo/server\": {\n      \"optional\": true\n    },\n    \"@azure/functions\": {\n      \"optional\": true\n    },\n    \"@deepkit/http\": {\n      \"optional\": true\n    },\n    \"@google-cloud/functions-framework\": {\n      \"optional\": true\n    },\n    \"@hapi/hapi\": {\n      \"optional\": true\n    },\n    \"@trpc/server\": {\n      \"optional\": true\n    },\n    \"@types/aws-lambda\": {\n      \"optional\": true\n    },\n    \"@types/express\": {\n      \"optional\": true\n    },\n    \"@types/hapi\": {\n      \"optional\": true\n    },\n    \"@types/koa\": {\n      \"optional\": true\n    },\n    \"body-parser\": {\n      \"optional\": true\n    },\n    \"cors\": {\n      \"optional\": true\n    },\n    \"express\": {\n      \"optional\": true\n    },\n    \"fastify\": {\n      \"optional\": true\n    },\n    \"firebase-admin\": {\n      \"optional\": true\n    },\n    \"firebase-functions\": {\n      \"optional\": true\n    },\n    \"http-errors\": {\n      \"optional\": true\n    },\n    \"koa\": {\n      \"optional\": true\n    },\n    \"reflect-metadata\": {\n      \"optional\": true\n    }\n  },\n  \"config\": {\n    \"commitizen\": {\n      \"path\": \"./node_modules/cz-conventional-changelog\"\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"exports\": {\n    \".\": {\n      \"import\": {\n        \"types\": \"./lib/index.d.ts\",\n        \"default\": \"./lib/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/index.d.cts\",\n        \"default\": \"./lib/index.cjs\"\n      }\n    },\n    \"./adapters/apollo-server\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/apollo-server/index.d.ts\",\n        \"default\": \"./lib/adapters/apollo-server/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/apollo-server/index.d.cts\",\n        \"default\": \"./lib/adapters/apollo-server/index.cjs\"\n      }\n    },\n    \"./lib/adapters/apollo-server\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/apollo-server/index.d.ts\",\n        \"default\": \"./lib/adapters/apollo-server/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/apollo-server/index.d.cts\",\n        \"default\": \"./lib/adapters/apollo-server/index.cjs\"\n      }\n    },\n    \"./adapters/aws\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/aws/index.d.ts\",\n        \"default\": \"./lib/adapters/aws/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/aws/index.d.cts\",\n        \"default\": \"./lib/adapters/aws/index.cjs\"\n      }\n    },\n    \"./lib/adapters/aws\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/aws/index.d.ts\",\n        \"default\": \"./lib/adapters/aws/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/aws/index.d.cts\",\n        \"default\": \"./lib/adapters/aws/index.cjs\"\n      }\n    },\n    \"./adapters/azure\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/azure/index.d.ts\",\n        \"default\": \"./lib/adapters/azure/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/azure/index.d.cts\",\n        \"default\": \"./lib/adapters/azure/index.cjs\"\n      }\n    },\n    \"./lib/adapters/azure\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/azure/index.d.ts\",\n        \"default\": \"./lib/adapters/azure/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/azure/index.d.cts\",\n        \"default\": \"./lib/adapters/azure/index.cjs\"\n      }\n    },\n    \"./adapters/digital-ocean\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/digital-ocean/index.d.ts\",\n        \"default\": \"./lib/adapters/digital-ocean/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/digital-ocean/index.d.cts\",\n        \"default\": \"./lib/adapters/digital-ocean/index.cjs\"\n      }\n    },\n    \"./lib/adapters/digital-ocean\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/digital-ocean/index.d.ts\",\n        \"default\": \"./lib/adapters/digital-ocean/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/digital-ocean/index.d.cts\",\n        \"default\": \"./lib/adapters/digital-ocean/index.cjs\"\n      }\n    },\n    \"./adapters/dummy\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/dummy/index.d.ts\",\n        \"default\": \"./lib/adapters/dummy/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/dummy/index.d.cts\",\n        \"default\": \"./lib/adapters/dummy/index.cjs\"\n      }\n    },\n    \"./lib/adapters/dummy\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/dummy/index.d.ts\",\n        \"default\": \"./lib/adapters/dummy/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/dummy/index.d.cts\",\n        \"default\": \"./lib/adapters/dummy/index.cjs\"\n      }\n    },\n    \"./adapters/huawei\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/huawei/index.d.ts\",\n        \"default\": \"./lib/adapters/huawei/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/huawei/index.d.cts\",\n        \"default\": \"./lib/adapters/huawei/index.cjs\"\n      }\n    },\n    \"./lib/adapters/huawei\": {\n      \"import\": {\n        \"types\": \"./lib/adapters/huawei/index.d.ts\",\n        \"default\": \"./lib/adapters/huawei/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/adapters/huawei/index.d.cts\",\n        \"default\": \"./lib/adapters/huawei/index.cjs\"\n      }\n    },\n    \"./frameworks/apollo-server\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/apollo-server/index.d.ts\",\n        \"default\": \"./lib/frameworks/apollo-server/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/apollo-server/index.d.cts\",\n        \"default\": \"./lib/frameworks/apollo-server/index.cjs\"\n      }\n    },\n    \"./lib/frameworks/apollo-server\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/apollo-server/index.d.ts\",\n        \"default\": \"./lib/frameworks/apollo-server/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/apollo-server/index.d.cts\",\n        \"default\": \"./lib/frameworks/apollo-server/index.cjs\"\n      }\n    },\n    \"./frameworks/body-parser\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/body-parser/index.d.ts\",\n        \"default\": \"./lib/frameworks/body-parser/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/body-parser/index.d.cts\",\n        \"default\": \"./lib/frameworks/body-parser/index.cjs\"\n      }\n    },\n    \"./lib/frameworks/body-parser\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/body-parser/index.d.ts\",\n        \"default\": \"./lib/frameworks/body-parser/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/body-parser/index.d.cts\",\n        \"default\": \"./lib/frameworks/body-parser/index.cjs\"\n      }\n    },\n    \"./frameworks/cors\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/cors/index.d.ts\",\n        \"default\": \"./lib/frameworks/cors/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/cors/index.d.cts\",\n        \"default\": \"./lib/frameworks/cors/index.cjs\"\n      }\n    },\n    \"./lib/frameworks/cors\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/cors/index.d.ts\",\n        \"default\": \"./lib/frameworks/cors/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/cors/index.d.cts\",\n        \"default\": \"./lib/frameworks/cors/index.cjs\"\n      }\n    },\n    \"./frameworks/deepkit\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/deepkit/index.d.ts\",\n        \"default\": \"./lib/frameworks/deepkit/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/deepkit/index.d.cts\",\n        \"default\": \"./lib/frameworks/deepkit/index.cjs\"\n      }\n    },\n    \"./lib/frameworks/deepkit\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/deepkit/index.d.ts\",\n        \"default\": \"./lib/frameworks/deepkit/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/deepkit/index.d.cts\",\n        \"default\": \"./lib/frameworks/deepkit/index.cjs\"\n      }\n    },\n    \"./frameworks/express\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/express/index.d.ts\",\n        \"default\": \"./lib/frameworks/express/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/express/index.d.cts\",\n        \"default\": \"./lib/frameworks/express/index.cjs\"\n      }\n    },\n    \"./lib/frameworks/express\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/express/index.d.ts\",\n        \"default\": \"./lib/frameworks/express/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/express/index.d.cts\",\n        \"default\": \"./lib/frameworks/express/index.cjs\"\n      }\n    },\n    \"./frameworks/fastify\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/fastify/index.d.ts\",\n        \"default\": \"./lib/frameworks/fastify/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/fastify/index.d.cts\",\n        \"default\": \"./lib/frameworks/fastify/index.cjs\"\n      }\n    },\n    \"./lib/frameworks/fastify\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/fastify/index.d.ts\",\n        \"default\": \"./lib/frameworks/fastify/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/fastify/index.d.cts\",\n        \"default\": \"./lib/frameworks/fastify/index.cjs\"\n      }\n    },\n    \"./frameworks/hapi\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/hapi/index.d.ts\",\n        \"default\": \"./lib/frameworks/hapi/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/hapi/index.d.cts\",\n        \"default\": \"./lib/frameworks/hapi/index.cjs\"\n      }\n    },\n    \"./lib/frameworks/hapi\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/hapi/index.d.ts\",\n        \"default\": \"./lib/frameworks/hapi/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/hapi/index.d.cts\",\n        \"default\": \"./lib/frameworks/hapi/index.cjs\"\n      }\n    },\n    \"./frameworks/koa\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/koa/index.d.ts\",\n        \"default\": \"./lib/frameworks/koa/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/koa/index.d.cts\",\n        \"default\": \"./lib/frameworks/koa/index.cjs\"\n      }\n    },\n    \"./lib/frameworks/koa\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/koa/index.d.ts\",\n        \"default\": \"./lib/frameworks/koa/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/koa/index.d.cts\",\n        \"default\": \"./lib/frameworks/koa/index.cjs\"\n      }\n    },\n    \"./frameworks/lazy\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/lazy/index.d.ts\",\n        \"default\": \"./lib/frameworks/lazy/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/lazy/index.d.cts\",\n        \"default\": \"./lib/frameworks/lazy/index.cjs\"\n      }\n    },\n    \"./lib/frameworks/lazy\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/lazy/index.d.ts\",\n        \"default\": \"./lib/frameworks/lazy/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/lazy/index.d.cts\",\n        \"default\": \"./lib/frameworks/lazy/index.cjs\"\n      }\n    },\n    \"./frameworks/polka\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/polka/index.d.ts\",\n        \"default\": \"./lib/frameworks/polka/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/polka/index.d.cts\",\n        \"default\": \"./lib/frameworks/polka/index.cjs\"\n      }\n    },\n    \"./lib/frameworks/polka\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/polka/index.d.ts\",\n        \"default\": \"./lib/frameworks/polka/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/polka/index.d.cts\",\n        \"default\": \"./lib/frameworks/polka/index.cjs\"\n      }\n    },\n    \"./frameworks/trpc\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/trpc/index.d.ts\",\n        \"default\": \"./lib/frameworks/trpc/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/trpc/index.d.cts\",\n        \"default\": \"./lib/frameworks/trpc/index.cjs\"\n      }\n    },\n    \"./lib/frameworks/trpc\": {\n      \"import\": {\n        \"types\": \"./lib/frameworks/trpc/index.d.ts\",\n        \"default\": \"./lib/frameworks/trpc/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/frameworks/trpc/index.d.cts\",\n        \"default\": \"./lib/frameworks/trpc/index.cjs\"\n      }\n    },\n    \"./handlers/aws\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/aws/index.d.ts\",\n        \"default\": \"./lib/handlers/aws/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/aws/index.d.cts\",\n        \"default\": \"./lib/handlers/aws/index.cjs\"\n      }\n    },\n    \"./lib/handlers/aws\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/aws/index.d.ts\",\n        \"default\": \"./lib/handlers/aws/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/aws/index.d.cts\",\n        \"default\": \"./lib/handlers/aws/index.cjs\"\n      }\n    },\n    \"./handlers/azure\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/azure/index.d.ts\",\n        \"default\": \"./lib/handlers/azure/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/azure/index.d.cts\",\n        \"default\": \"./lib/handlers/azure/index.cjs\"\n      }\n    },\n    \"./lib/handlers/azure\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/azure/index.d.ts\",\n        \"default\": \"./lib/handlers/azure/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/azure/index.d.cts\",\n        \"default\": \"./lib/handlers/azure/index.cjs\"\n      }\n    },\n    \"./handlers/default\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/default/index.d.ts\",\n        \"default\": \"./lib/handlers/default/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/default/index.d.cts\",\n        \"default\": \"./lib/handlers/default/index.cjs\"\n      }\n    },\n    \"./lib/handlers/default\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/default/index.d.ts\",\n        \"default\": \"./lib/handlers/default/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/default/index.d.cts\",\n        \"default\": \"./lib/handlers/default/index.cjs\"\n      }\n    },\n    \"./handlers/digital-ocean\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/digital-ocean/index.d.ts\",\n        \"default\": \"./lib/handlers/digital-ocean/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/digital-ocean/index.d.cts\",\n        \"default\": \"./lib/handlers/digital-ocean/index.cjs\"\n      }\n    },\n    \"./lib/handlers/digital-ocean\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/digital-ocean/index.d.ts\",\n        \"default\": \"./lib/handlers/digital-ocean/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/digital-ocean/index.d.cts\",\n        \"default\": \"./lib/handlers/digital-ocean/index.cjs\"\n      }\n    },\n    \"./handlers/firebase\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/firebase/index.d.ts\",\n        \"default\": \"./lib/handlers/firebase/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/firebase/index.d.cts\",\n        \"default\": \"./lib/handlers/firebase/index.cjs\"\n      }\n    },\n    \"./lib/handlers/firebase\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/firebase/index.d.ts\",\n        \"default\": \"./lib/handlers/firebase/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/firebase/index.d.cts\",\n        \"default\": \"./lib/handlers/firebase/index.cjs\"\n      }\n    },\n    \"./handlers/gcp\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/gcp/index.d.ts\",\n        \"default\": \"./lib/handlers/gcp/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/gcp/index.d.cts\",\n        \"default\": \"./lib/handlers/gcp/index.cjs\"\n      }\n    },\n    \"./lib/handlers/gcp\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/gcp/index.d.ts\",\n        \"default\": \"./lib/handlers/gcp/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/gcp/index.d.cts\",\n        \"default\": \"./lib/handlers/gcp/index.cjs\"\n      }\n    },\n    \"./handlers/huawei\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/huawei/index.d.ts\",\n        \"default\": \"./lib/handlers/huawei/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/huawei/index.d.cts\",\n        \"default\": \"./lib/handlers/huawei/index.cjs\"\n      }\n    },\n    \"./lib/handlers/huawei\": {\n      \"import\": {\n        \"types\": \"./lib/handlers/huawei/index.d.ts\",\n        \"default\": \"./lib/handlers/huawei/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/handlers/huawei/index.d.cts\",\n        \"default\": \"./lib/handlers/huawei/index.cjs\"\n      }\n    },\n    \"./resolvers/aws-context\": {\n      \"import\": {\n        \"types\": \"./lib/resolvers/aws-context/index.d.ts\",\n        \"default\": \"./lib/resolvers/aws-context/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/resolvers/aws-context/index.d.cts\",\n        \"default\": \"./lib/resolvers/aws-context/index.cjs\"\n      }\n    },\n    \"./lib/resolvers/aws-context\": {\n      \"import\": {\n        \"types\": \"./lib/resolvers/aws-context/index.d.ts\",\n        \"default\": \"./lib/resolvers/aws-context/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/resolvers/aws-context/index.d.cts\",\n        \"default\": \"./lib/resolvers/aws-context/index.cjs\"\n      }\n    },\n    \"./resolvers/callback\": {\n      \"import\": {\n        \"types\": \"./lib/resolvers/callback/index.d.ts\",\n        \"default\": \"./lib/resolvers/callback/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/resolvers/callback/index.d.cts\",\n        \"default\": \"./lib/resolvers/callback/index.cjs\"\n      }\n    },\n    \"./lib/resolvers/callback\": {\n      \"import\": {\n        \"types\": \"./lib/resolvers/callback/index.d.ts\",\n        \"default\": \"./lib/resolvers/callback/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/resolvers/callback/index.d.cts\",\n        \"default\": \"./lib/resolvers/callback/index.cjs\"\n      }\n    },\n    \"./resolvers/dummy\": {\n      \"import\": {\n        \"types\": \"./lib/resolvers/dummy/index.d.ts\",\n        \"default\": \"./lib/resolvers/dummy/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/resolvers/dummy/index.d.cts\",\n        \"default\": \"./lib/resolvers/dummy/index.cjs\"\n      }\n    },\n    \"./lib/resolvers/dummy\": {\n      \"import\": {\n        \"types\": \"./lib/resolvers/dummy/index.d.ts\",\n        \"default\": \"./lib/resolvers/dummy/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/resolvers/dummy/index.d.cts\",\n        \"default\": \"./lib/resolvers/dummy/index.cjs\"\n      }\n    },\n    \"./resolvers/promise\": {\n      \"import\": {\n        \"types\": \"./lib/resolvers/promise/index.d.ts\",\n        \"default\": \"./lib/resolvers/promise/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/resolvers/promise/index.d.cts\",\n        \"default\": \"./lib/resolvers/promise/index.cjs\"\n      }\n    },\n    \"./lib/resolvers/promise\": {\n      \"import\": {\n        \"types\": \"./lib/resolvers/promise/index.d.ts\",\n        \"default\": \"./lib/resolvers/promise/index.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./lib/resolvers/promise/index.d.cts\",\n        \"default\": \"./lib/resolvers/promise/index.cjs\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "release-please-config.json",
    "content": "{\n  \"packages\": {\n    \".\": {\n      \"release-type\": \"node\",\n      \"bump-minor-pre-major\": false,\n      \"bump-patch-for-minor-pre-major\": false,\n      \"draft\": false,\n      \"prerelease\": false,\n      \"draft-pull-request\": true,\n      \"include-component-in-tag\": false,\n      \"include-v-in-tag\": true,\n      \"separate-pull-requests\": false,\n      \"skip-github-release\": false,\n      \"versioning\": \"default\",\n      \"pull-request-header\": \":robot: I have created a release *beep* *boop*\",\n      \"pull-request-title-pattern\": \"chore${scope}: release${component} ${version}\",\n      \"changelog-path\": \"CHANGELOG.md\",\n      \"changelog-host\": \"https://github.com\",\n      \"changelog-type\": \"default\",\n      \"changelog-sections\": [\n        {\n          \"type\": \"feat\",\n          \"section\": \"Features\"\n        },\n        {\n          \"type\": \"feature\",\n          \"section\": \"Features\"\n        },\n        {\n          \"type\": \"fix\",\n          \"section\": \"Bug Fixes\"\n        },\n        {\n          \"type\": \"perf\",\n          \"section\": \"Performance Improvements\"\n        },\n        {\n          \"type\": \"revert\",\n          \"section\": \"Reverts\"\n        },\n        {\n          \"type\": \"docs\",\n          \"section\": \"Documentation\"\n        },\n        {\n          \"type\": \"style\",\n          \"section\": \"Styles\"\n        },\n        {\n          \"type\": \"chore\",\n          \"section\": \"Miscellaneous Chores\"\n        },\n        {\n          \"type\": \"refactor\",\n          \"section\": \"Code Refactoring\"\n        },\n        {\n          \"type\": \"test\",\n          \"section\": \"Tests\"\n        },\n        {\n          \"type\": \"build\",\n          \"section\": \"Build System\"\n        },\n        {\n          \"type\": \"ci\",\n          \"section\": \"Continuous Integration\"\n        }\n      ]\n    }\n  },\n  \"$schema\": \"https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json\"\n}\n"
  },
  {
    "path": "scripts/generate-api-pages.ts",
    "content": "import { writeFileSync } from 'fs';\nimport { resolve } from 'path';\nimport {\n  ApiDocumentedItem,\n  ApiItem,\n  ApiModel,\n} from '@microsoft/api-extractor-model';\nimport { DocNode, DocNodeKind, DocPlainText } from '@microsoft/tsdoc';\n\nconst apiModelPath = resolve('.', 'temp', 'serverless-adapter.api.json');\nconst outputFile = resolve('.', 'www', 'sidebar-api-generated.js');\n\ntype BreadcrumbItem = {\n  breadcrumbs: string[];\n  apiMember: ApiItem;\n};\n\nfunction isPlainTextNode(block: DocNode): block is DocPlainText {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n  return block.kind === DocNodeKind.PlainText;\n}\n\nfunction getBreadcrumbsWithApiItem(apiModel: ApiModel): BreadcrumbItem[] {\n  const breadcrumbs: BreadcrumbItem[] = [];\n\n  for (const apiPackage of apiModel.members) {\n    for (const apiEntrypoint of apiPackage.members) {\n      for (const apiMember of apiEntrypoint.members) {\n        const apiDocumentedItem = apiMember as ApiDocumentedItem;\n\n        if (!apiDocumentedItem.tsdocComment) continue;\n\n        const breadcrumb = apiDocumentedItem.tsdocComment.customBlocks.find(\n          block => block.blockTag.tagName === '@breadcrumb',\n        );\n\n        if (!breadcrumb) continue;\n\n        const breadcrumbContent = breadcrumb.content\n          .getChildNodes()\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n          .filter(block => block.kind === DocNodeKind.Paragraph)\n          // @ts-ignore\n          .reduce((acc, block) => [...acc, ...block.getChildNodes()], [])\n          // @ts-ignore\n          .filter(isPlainTextNode)\n          .map((plainText: DocPlainText) => plainText.text)\n          .join('');\n\n        breadcrumbs.push({\n          breadcrumbs: breadcrumbContent\n            .split('/')\n            .map(section => section.trimLeft().trimRight()),\n          apiMember,\n        });\n      }\n    }\n  }\n\n  return breadcrumbs;\n}\n\ntype SidebarItem = {\n  type: string;\n  label: string;\n  link?: {\n    type: string;\n    id: string;\n  };\n  items: Sidebar[];\n};\n\ntype Sidebar = SidebarItem;\n\nfunction build(): void {\n  const apiModel = new ApiModel();\n\n  apiModel.loadPackage(apiModelPath);\n\n  const breadcrumbsWithApiItems = getBreadcrumbsWithApiItem(apiModel);\n\n  const pages: Sidebar[] = [];\n\n  for (const breadcrumbWithApiItem of breadcrumbsWithApiItems) {\n    let lastPage: SidebarItem | undefined;\n\n    for (const breadcrumb of breadcrumbWithApiItem.breadcrumbs) {\n      const newPage: SidebarItem = {\n        type: 'category',\n        label: breadcrumb,\n        items: [],\n        link: {\n          id: `./api/${breadcrumb}`,\n          type: 'doc',\n        },\n      };\n\n      if (lastPage) {\n        let subpage = lastPage.items.find(page => page.label === breadcrumb);\n\n        if (!subpage) {\n          subpage = newPage;\n\n          lastPage.items.push(subpage);\n        }\n\n        lastPage = subpage;\n      } else {\n        const oldPage = pages.find(page => page.label === breadcrumb);\n\n        if (oldPage) lastPage = oldPage;\n        else {\n          lastPage = newPage;\n\n          pages.push(lastPage);\n        }\n      }\n    }\n\n    if (!lastPage) {\n      throw new Error(\n        `Breadcrumb was configured incorrectly. Error found in ${breadcrumbWithApiItem.apiMember.displayName}.`,\n      );\n    }\n\n    lastPage.items.push({\n      type: 'category',\n      label: breadcrumbWithApiItem.apiMember.displayName,\n      items: [],\n    });\n  }\n\n  writeFileSync(outputFile, `export default ${JSON.stringify(pages)}`);\n}\n\nbuild();\n"
  },
  {
    "path": "scripts/generate-markdown.ts",
    "content": "import { readFileSync, writeFileSync } from 'fs';\nimport { join, resolve } from 'path';\nimport { ApiModel } from '@microsoft/api-extractor-model';\nimport { CustomMarkdownDocumenter } from './libs/CustomMarkdownDocumenter';\n\nconst apiModelPath = resolve('.', 'temp', 'serverless-adapter.api.json');\nconst outputFolder = resolve('.', 'www', 'docs', 'api');\n\nfunction build(): void {\n  const apiModel = new ApiModel();\n\n  apiModel.loadPackage(apiModelPath);\n\n  const markdown = new CustomMarkdownDocumenter({\n    apiModel,\n    outputFolder,\n    documenterConfig: undefined,\n  });\n\n  markdown.generateFiles();\n\n  const filename = join(outputFolder, 'Introduction.md');\n  const introductionMarkdownContent = readFileSync(filename);\n\n  const introductionContent = `---\\ntitle: Introduction\\nsidebar_position: -1\\n---\\n\\n${introductionMarkdownContent}`;\n\n  writeFileSync(filename, introductionContent);\n}\n\nbuild();\n"
  },
  {
    "path": "scripts/libs/CustomMarkdownDocumenter.ts",
    "content": "import * as path from 'path';\nimport {\n  type IMarkdownDocumenterFeatureOnBeforeWritePageArgs,\n  MarkdownDocumenterAccessor,\n  MarkdownDocumenterFeatureContext,\n} from '@microsoft/api-documenter/lib';\nimport { DocumenterConfig } from '@microsoft/api-documenter/lib/documenters/DocumenterConfig';\nimport { CustomDocNodes } from '@microsoft/api-documenter/lib/nodes/CustomDocNodeKind';\nimport { DocEmphasisSpan } from '@microsoft/api-documenter/lib/nodes/DocEmphasisSpan';\nimport { DocHeading } from '@microsoft/api-documenter/lib/nodes/DocHeading';\nimport { DocNoteBox } from '@microsoft/api-documenter/lib/nodes/DocNoteBox';\nimport { DocTable } from '@microsoft/api-documenter/lib/nodes/DocTable';\nimport { DocTableCell } from '@microsoft/api-documenter/lib/nodes/DocTableCell';\nimport { DocTableRow } from '@microsoft/api-documenter/lib/nodes/DocTableRow';\nimport { PluginLoader } from '@microsoft/api-documenter/lib/plugin/PluginLoader';\nimport { Utilities } from '@microsoft/api-documenter/lib/utils/Utilities';\nimport {\n  ApiClass,\n  ApiDeclaredItem,\n  ApiDocumentedItem,\n  ApiEnum,\n  ApiInterface,\n  ApiItem,\n  ApiItemKind,\n  ApiModel,\n  ApiNamespace,\n  ApiOptionalMixin,\n  ApiPackage,\n  ApiParameterListMixin,\n  ApiReleaseTagMixin,\n  ApiReturnTypeMixin,\n  ApiTypeAlias,\n  Excerpt,\n  ExcerptToken,\n  ExcerptTokenKind,\n  type IResolveDeclarationReferenceResult,\n  ReleaseTag,\n} from '@microsoft/api-extractor-model';\nimport {\n  DocBlock,\n  DocCodeSpan,\n  DocComment,\n  DocFencedCode,\n  DocLinkTag,\n  DocNodeContainer,\n  DocNodeKind,\n  DocParagraph,\n  DocPlainText,\n  DocSection,\n  StandardTags,\n  StringBuilder,\n  TSDocConfiguration,\n} from '@microsoft/tsdoc';\nimport {\n  FileSystem,\n  NewlineKind,\n  PackageName,\n} from '@rushstack/node-core-library';\nimport { CustomUtilities } from './CustomUtilities';\nimport { MarkdownEmitter } from './MarkdownEmitter';\n\nexport interface IMarkdownDocumenterOptions {\n  apiModel: ApiModel;\n  documenterConfig: DocumenterConfig | undefined;\n  outputFolder: string;\n}\n\n/**\n * Renders API documentation in the Markdown file format.\n * For more info:  https://en.wikipedia.org/wiki/Markdown\n */\nexport class CustomMarkdownDocumenter {\n  public constructor(options: IMarkdownDocumenterOptions) {\n    this._apiModel = options.apiModel;\n    this._documenterConfig = options.documenterConfig;\n    this._outputFolder = options.outputFolder;\n    this._tsdocConfiguration = CustomDocNodes.configuration;\n    this._markdownEmitter = new MarkdownEmitter(this._apiModel);\n\n    this._pluginLoader = new PluginLoader();\n  }\n\n  private readonly _apiModel: ApiModel;\n  private readonly _documenterConfig: DocumenterConfig | undefined;\n  private readonly _tsdocConfiguration: TSDocConfiguration;\n  private readonly _markdownEmitter: MarkdownEmitter;\n  private readonly _outputFolder: string;\n  private readonly _pluginLoader: PluginLoader;\n\n  public generateFiles(): void {\n    if (this._documenterConfig) {\n      this._pluginLoader.load(this._documenterConfig, () => {\n        return new MarkdownDocumenterFeatureContext({\n          apiModel: this._apiModel,\n          outputFolder: this._outputFolder,\n          documenter: new MarkdownDocumenterAccessor({\n            getLinkForApiItem: (apiItem: ApiItem) => {\n              return this._getLinkFilenameForApiItem(apiItem);\n            },\n          }),\n        });\n      });\n    }\n\n    this._deleteOldOutputFiles();\n\n    this._writeApiItemPage(this._apiModel);\n\n    if (this._pluginLoader.markdownDocumenterFeature)\n      this._pluginLoader.markdownDocumenterFeature.onFinished({});\n  }\n\n  private _writeApiItemPage(apiItem: ApiItem, parentOutput?: DocSection): void {\n    const configuration: TSDocConfiguration = this._tsdocConfiguration;\n    const output: DocSection =\n      parentOutput ||\n      new DocSection({\n        configuration: this._tsdocConfiguration,\n      });\n\n    if (!parentOutput) this._writeBreadcrumb(output, apiItem);\n\n    const scopedName: string = apiItem.displayName;\n\n    switch (apiItem.kind) {\n      case ApiItemKind.Class:\n        output.appendNode(\n          new DocHeading({ configuration, title: `(class) ${scopedName}` }),\n        );\n        break;\n      case ApiItemKind.Enum:\n        output.appendNode(\n          new DocHeading({ configuration, title: `(enum) ${scopedName}` }),\n        );\n        break;\n      case ApiItemKind.Interface:\n        output.appendNode(\n          new DocHeading({ configuration, title: `(interface) ${scopedName}` }),\n        );\n        break;\n      case ApiItemKind.Constructor:\n      case ApiItemKind.ConstructSignature:\n        output.appendNode(new DocHeading({ configuration, title: scopedName }));\n        break;\n      case ApiItemKind.Method:\n      case ApiItemKind.MethodSignature:\n        output.appendNode(\n          new DocHeading({ configuration, title: `(method) ${scopedName}` }),\n        );\n        break;\n      case ApiItemKind.Function:\n        output.appendNode(\n          new DocHeading({ configuration, title: `(function) ${scopedName}` }),\n        );\n        break;\n      case ApiItemKind.Model:\n        output.appendNode(\n          new DocHeading({ configuration, title: 'API Reference' }),\n        );\n        break;\n      case ApiItemKind.Namespace:\n        output.appendNode(\n          new DocHeading({ configuration, title: `(namespace) ${scopedName}` }),\n        );\n        break;\n      case ApiItemKind.Package:\n        console.log(`Writing ${apiItem.displayName} package`);\n        const unscopedPackageName: string = PackageName.getUnscopedName(\n          apiItem.displayName,\n        );\n        output.appendNode(\n          new DocHeading({\n            configuration,\n            title: `(package) ${unscopedPackageName}`,\n          }),\n        );\n        break;\n      case ApiItemKind.Property:\n      case ApiItemKind.PropertySignature:\n        output.appendNode(\n          new DocHeading({ configuration, title: `(property) ${scopedName}` }),\n        );\n        break;\n      case ApiItemKind.TypeAlias:\n        output.appendNode(\n          new DocHeading({ configuration, title: `(type) ${scopedName}` }),\n        );\n        break;\n      case ApiItemKind.Variable:\n        output.appendNode(\n          new DocHeading({ configuration, title: `(variable) ${scopedName}` }),\n        );\n        break;\n      default:\n        throw new Error('Unsupported API item kind: ' + apiItem.kind);\n    }\n\n    if (ApiReleaseTagMixin.isBaseClassOf(apiItem)) {\n      if (apiItem.releaseTag === ReleaseTag.Beta)\n        this._writeBetaWarning(output);\n    }\n\n    const decoratorBlocks: DocBlock[] = [];\n\n    if (apiItem instanceof ApiDocumentedItem) {\n      const tsdocComment: DocComment | undefined = apiItem.tsdocComment;\n\n      if (tsdocComment) {\n        decoratorBlocks.push(\n          ...tsdocComment.customBlocks.filter(\n            block =>\n              block.blockTag.tagNameWithUpperCase ===\n              StandardTags.decorator.tagNameWithUpperCase,\n          ),\n        );\n\n        if (tsdocComment.deprecatedBlock) {\n          output.appendNode(\n            new DocNoteBox({ configuration: this._tsdocConfiguration }, [\n              new DocParagraph({ configuration: this._tsdocConfiguration }, [\n                new DocPlainText({\n                  configuration: this._tsdocConfiguration,\n                  text: 'Warning: This API is now obsolete. ',\n                }),\n              ]),\n              ...tsdocComment.deprecatedBlock.content.nodes,\n            ]),\n          );\n        }\n\n        this._appendSection(output, tsdocComment.summarySection);\n      }\n    }\n\n    if (apiItem instanceof ApiDeclaredItem) {\n      if (apiItem.excerpt.text.length > 0) {\n        output.appendNode(\n          new DocParagraph({ configuration }, [\n            new DocEmphasisSpan({ configuration, bold: true }, [\n              new DocPlainText({ configuration, text: 'Signature:' }),\n            ]),\n          ]),\n        );\n        output.appendNode(\n          new DocFencedCode({\n            configuration,\n            code: apiItem.getExcerptWithModifiers(),\n            language: 'typescript',\n          }),\n        );\n      }\n\n      this._writeHeritageTypes(output, apiItem);\n    }\n\n    if (decoratorBlocks.length > 0) {\n      output.appendNode(\n        new DocParagraph({ configuration }, [\n          new DocEmphasisSpan({ configuration, bold: true }, [\n            new DocPlainText({ configuration, text: 'Decorators:' }),\n          ]),\n        ]),\n      );\n      for (const decoratorBlock of decoratorBlocks)\n        output.appendNodes(decoratorBlock.content.nodes);\n    }\n\n    let appendRemarks: boolean = true;\n    switch (apiItem.kind) {\n      case ApiItemKind.Class:\n      case ApiItemKind.Interface:\n      case ApiItemKind.Namespace:\n      case ApiItemKind.Package:\n        this._writeRemarksSection(output, apiItem);\n        appendRemarks = false;\n        break;\n    }\n\n    switch (apiItem.kind) {\n      case ApiItemKind.Class:\n        this._writeClassTables(output, apiItem as ApiClass);\n        break;\n      case ApiItemKind.Enum:\n        this._writeEnumTables(output, apiItem as ApiEnum);\n        break;\n      case ApiItemKind.Interface:\n        this._writeInterfaceTables(output, apiItem as ApiInterface);\n        break;\n      case ApiItemKind.Constructor:\n      case ApiItemKind.ConstructSignature:\n      case ApiItemKind.Method:\n      case ApiItemKind.MethodSignature:\n      case ApiItemKind.Function:\n        this._writeParameterTables(output, apiItem as ApiParameterListMixin);\n        this._writeThrowsSection(output, apiItem);\n        break;\n      case ApiItemKind.Namespace:\n        this._writePackageOrNamespaceTables(output, apiItem as ApiNamespace);\n        break;\n      case ApiItemKind.Model:\n        this._writeModelTable(output, apiItem as ApiModel);\n        break;\n      case ApiItemKind.Package:\n        this._writePackageOrNamespaceTables(output, apiItem as ApiPackage);\n        break;\n      case ApiItemKind.Property:\n      case ApiItemKind.PropertySignature:\n        break;\n      case ApiItemKind.TypeAlias:\n        break;\n      case ApiItemKind.Variable:\n        break;\n      default:\n        throw new Error(`Unsupported API item kind: ${apiItem.kind}`);\n    }\n\n    if (appendRemarks) this._writeRemarksSection(output, apiItem);\n\n    const filename: string = path.join(\n      this._outputFolder,\n      this._getFilenameForApiItem(apiItem, true),\n    );\n    const stringBuilder: StringBuilder = new StringBuilder();\n\n    stringBuilder.append(\n      '<!-- Do not edit this file. It is automatically generated by API Documenter. -->\\n\\n',\n    );\n\n    this._markdownEmitter.emit(stringBuilder, output, {\n      contextApiItem: apiItem,\n      onGetFilenameForApiItem: (apiItemForFilename: ApiItem) => {\n        return this._getLinkFilenameForApiItem(apiItemForFilename);\n      },\n    });\n\n    let pageContent: string = stringBuilder.toString();\n\n    if (this._pluginLoader.markdownDocumenterFeature) {\n      // Allow the plugin to customize the pageContent\n      const eventArgs: IMarkdownDocumenterFeatureOnBeforeWritePageArgs = {\n        apiItem: apiItem,\n        outputFilename: filename,\n        pageContent: pageContent,\n      };\n      this._pluginLoader.markdownDocumenterFeature.onBeforeWritePage(eventArgs);\n      pageContent = eventArgs.pageContent;\n    }\n\n    if (apiItem.kind == ApiItemKind.Model) return;\n\n    if (parentOutput) return;\n\n    if (filename.includes('ignored.md')) return;\n\n    FileSystem.writeFile(filename, pageContent.replaceAll('{', '\\\\{'), {\n      ensureFolderExists: true,\n      convertLineEndings: this._documenterConfig\n        ? this._documenterConfig.newlineKind\n        : NewlineKind.CrLf,\n    });\n  }\n\n  private _writeHeritageTypes(\n    output: DocSection,\n    apiItem: ApiDeclaredItem,\n  ): void {\n    const configuration: TSDocConfiguration = this._tsdocConfiguration;\n\n    if (apiItem instanceof ApiClass) {\n      if (apiItem.extendsType) {\n        const extendsParagraph: DocParagraph = new DocParagraph(\n          { configuration },\n          [\n            new DocEmphasisSpan({ configuration, bold: true }, [\n              new DocPlainText({ configuration, text: 'Extends: ' }),\n            ]),\n          ],\n        );\n        this._appendExcerptWithHyperlinks(\n          extendsParagraph,\n          apiItem.extendsType.excerpt,\n        );\n        output.appendNode(extendsParagraph);\n      }\n      if (apiItem.implementsTypes.length > 0) {\n        const extendsParagraph: DocParagraph = new DocParagraph(\n          { configuration },\n          [\n            new DocEmphasisSpan({ configuration, bold: true }, [\n              new DocPlainText({ configuration, text: 'Implements: ' }),\n            ]),\n          ],\n        );\n        let needsComma: boolean = false;\n        for (const implementsType of apiItem.implementsTypes) {\n          if (needsComma) {\n            extendsParagraph.appendNode(\n              new DocPlainText({ configuration, text: ', ' }),\n            );\n          }\n          this._appendExcerptWithHyperlinks(\n            extendsParagraph,\n            implementsType.excerpt,\n          );\n          needsComma = true;\n        }\n        output.appendNode(extendsParagraph);\n      }\n    }\n\n    if (apiItem instanceof ApiInterface) {\n      if (apiItem.extendsTypes.length > 0) {\n        const extendsParagraph: DocParagraph = new DocParagraph(\n          { configuration },\n          [\n            new DocEmphasisSpan({ configuration, bold: true }, [\n              new DocPlainText({ configuration, text: 'Extends: ' }),\n            ]),\n          ],\n        );\n        let needsComma: boolean = false;\n        for (const extendsType of apiItem.extendsTypes) {\n          if (needsComma) {\n            extendsParagraph.appendNode(\n              new DocPlainText({ configuration, text: ', ' }),\n            );\n          }\n          this._appendExcerptWithHyperlinks(\n            extendsParagraph,\n            extendsType.excerpt,\n          );\n          needsComma = true;\n        }\n        output.appendNode(extendsParagraph);\n      }\n    }\n\n    if (apiItem instanceof ApiTypeAlias) {\n      const refs: ExcerptToken[] = apiItem.excerptTokens.filter(\n        token =>\n          token.kind === ExcerptTokenKind.Reference &&\n          token.canonicalReference &&\n          this._apiModel.resolveDeclarationReference(\n            token.canonicalReference,\n            undefined,\n          ).resolvedApiItem,\n      );\n      if (refs.length > 0) {\n        const referencesParagraph: DocParagraph = new DocParagraph(\n          { configuration },\n          [\n            new DocEmphasisSpan({ configuration, bold: true }, [\n              new DocPlainText({ configuration, text: 'References: ' }),\n            ]),\n          ],\n        );\n        let needsComma: boolean = false;\n        const visited: Set<string> = new Set();\n        for (const ref of refs) {\n          if (visited.has(ref.text)) continue;\n\n          visited.add(ref.text);\n\n          if (needsComma) {\n            referencesParagraph.appendNode(\n              new DocPlainText({ configuration, text: ', ' }),\n            );\n          }\n\n          this._appendExcerptTokenWithHyperlinks(referencesParagraph, ref);\n          needsComma = true;\n        }\n        output.appendNode(referencesParagraph);\n      }\n    }\n  }\n\n  private _writeRemarksSection(output: DocSection, apiItem: ApiItem): void {\n    if (apiItem instanceof ApiDocumentedItem) {\n      const tsdocComment: DocComment | undefined = apiItem.tsdocComment;\n\n      if (tsdocComment) {\n        // Write the @remarks block\n        if (tsdocComment.remarksBlock) {\n          output.appendNode(\n            new DocHeading({\n              configuration: this._tsdocConfiguration,\n              title: 'Remarks',\n            }),\n          );\n          this._appendSection(output, tsdocComment.remarksBlock.content);\n        }\n\n        // Write the @example blocks\n        const exampleBlocks: DocBlock[] = tsdocComment.customBlocks.filter(\n          x =>\n            x.blockTag.tagNameWithUpperCase ===\n            StandardTags.example.tagNameWithUpperCase,\n        );\n\n        let exampleNumber: number = 1;\n        for (const exampleBlock of exampleBlocks) {\n          const heading: string =\n            exampleBlocks.length > 1 ? `Example ${exampleNumber}` : 'Example';\n\n          output.appendNode(\n            new DocHeading({\n              configuration: this._tsdocConfiguration,\n              title: heading,\n            }),\n          );\n\n          this._appendSection(output, exampleBlock.content);\n\n          ++exampleNumber;\n        }\n      }\n    }\n  }\n\n  private _writeThrowsSection(output: DocSection, apiItem: ApiItem): void {\n    if (apiItem instanceof ApiDocumentedItem) {\n      const tsdocComment: DocComment | undefined = apiItem.tsdocComment;\n\n      if (tsdocComment) {\n        // Write the @throws blocks\n        const throwsBlocks: DocBlock[] = tsdocComment.customBlocks.filter(\n          x =>\n            x.blockTag.tagNameWithUpperCase ===\n            StandardTags.throws.tagNameWithUpperCase,\n        );\n\n        if (throwsBlocks.length > 0) {\n          const heading: string = 'Exceptions';\n          output.appendNode(\n            new DocHeading({\n              configuration: this._tsdocConfiguration,\n              title: heading,\n            }),\n          );\n\n          for (const throwsBlock of throwsBlocks)\n            this._appendSection(output, throwsBlock.content);\n        }\n      }\n    }\n  }\n\n  /**\n   * GENERATE PAGE: MODEL\n   */\n  private _writeModelTable(output: DocSection, apiModel: ApiModel): void {\n    const configuration: TSDocConfiguration = this._tsdocConfiguration;\n\n    const packagesTable: DocTable = new DocTable({\n      configuration,\n      headerTitles: ['Package', 'Description'],\n    });\n\n    for (const apiMember of apiModel.members) {\n      const row: DocTableRow = new DocTableRow({ configuration }, [\n        this._createTitleCell(apiMember),\n        this._createDescriptionCell(apiMember),\n      ]);\n\n      switch (apiMember.kind) {\n        case ApiItemKind.Package:\n          packagesTable.addRow(row);\n          this._writeApiItemPage(apiMember);\n          break;\n      }\n    }\n\n    if (packagesTable.rows.length > 0) {\n      output.appendNode(\n        new DocHeading({\n          configuration: this._tsdocConfiguration,\n          title: 'Packages',\n        }),\n      );\n      output.appendNode(packagesTable);\n    }\n  }\n\n  /**\n   * GENERATE PAGE: PACKAGE or NAMESPACE\n   */\n  private _writePackageOrNamespaceTables(\n    output: DocSection,\n    apiContainer: ApiPackage | ApiNamespace,\n  ): void {\n    const configuration: TSDocConfiguration = this._tsdocConfiguration;\n\n    const classesTable: DocTable = new DocTable({\n      configuration,\n      headerTitles: ['Class', 'Description'],\n    });\n\n    const enumerationsTable: DocTable = new DocTable({\n      configuration,\n      headerTitles: ['Enumeration', 'Description'],\n    });\n\n    const functionsTable: DocTable = new DocTable({\n      configuration,\n      headerTitles: ['Function', 'Description'],\n    });\n\n    const interfacesTable: DocTable = new DocTable({\n      configuration,\n      headerTitles: ['Interface', 'Description'],\n    });\n\n    const namespacesTable: DocTable = new DocTable({\n      configuration,\n      headerTitles: ['Namespace', 'Description'],\n    });\n\n    const variablesTable: DocTable = new DocTable({\n      configuration,\n      headerTitles: ['Variable', 'Description'],\n    });\n\n    const typeAliasesTable: DocTable = new DocTable({\n      configuration,\n      headerTitles: ['Type Alias', 'Description'],\n    });\n\n    const apiMembers: ReadonlyArray<ApiItem> =\n      apiContainer.kind === ApiItemKind.Package\n        ? (apiContainer as ApiPackage).entryPoints[0].members\n        : (apiContainer as ApiNamespace).members;\n\n    for (const apiMember of apiMembers) {\n      const name = Utilities.getConciseSignature(apiMember);\n\n      // ignore types generated by deepkit\n      if (name.startsWith('__')) continue;\n\n      const row: DocTableRow = new DocTableRow({ configuration }, [\n        this._createTitleCell(apiMember),\n        this._createDescriptionCell(apiMember),\n      ]);\n\n      switch (apiMember.kind) {\n        case ApiItemKind.Class:\n          classesTable.addRow(row);\n          this._writeApiItemPage(apiMember);\n          break;\n\n        case ApiItemKind.Enum:\n          enumerationsTable.addRow(row);\n          this._writeApiItemPage(apiMember);\n          break;\n\n        case ApiItemKind.Interface:\n          interfacesTable.addRow(row);\n          this._writeApiItemPage(apiMember);\n          break;\n\n        case ApiItemKind.Namespace:\n          namespacesTable.addRow(row);\n          this._writeApiItemPage(apiMember);\n          break;\n\n        case ApiItemKind.Function:\n          functionsTable.addRow(row);\n          this._writeApiItemPage(apiMember);\n          break;\n\n        case ApiItemKind.TypeAlias:\n          typeAliasesTable.addRow(row);\n          this._writeApiItemPage(apiMember);\n          break;\n\n        case ApiItemKind.Variable:\n          variablesTable.addRow(row);\n          this._writeApiItemPage(apiMember);\n          break;\n      }\n    }\n\n    if (classesTable.rows.length > 0) {\n      output.appendNode(\n        new DocHeading({\n          configuration: this._tsdocConfiguration,\n          title: 'Classes',\n        }),\n      );\n      output.appendNode(classesTable);\n    }\n\n    if (enumerationsTable.rows.length > 0) {\n      output.appendNode(\n        new DocHeading({\n          configuration: this._tsdocConfiguration,\n          title: 'Enumerations',\n        }),\n      );\n      output.appendNode(enumerationsTable);\n    }\n    if (functionsTable.rows.length > 0) {\n      output.appendNode(\n        new DocHeading({\n          configuration: this._tsdocConfiguration,\n          title: 'Functions',\n        }),\n      );\n      output.appendNode(functionsTable);\n    }\n\n    if (interfacesTable.rows.length > 0) {\n      output.appendNode(\n        new DocHeading({\n          configuration: this._tsdocConfiguration,\n          title: 'Interfaces',\n        }),\n      );\n      output.appendNode(interfacesTable);\n    }\n\n    if (namespacesTable.rows.length > 0) {\n      output.appendNode(\n        new DocHeading({\n          configuration: this._tsdocConfiguration,\n          title: 'Namespaces',\n        }),\n      );\n      output.appendNode(namespacesTable);\n    }\n\n    if (variablesTable.rows.length > 0) {\n      output.appendNode(\n        new DocHeading({\n          configuration: this._tsdocConfiguration,\n          title: 'Variables',\n        }),\n      );\n      output.appendNode(variablesTable);\n    }\n\n    if (typeAliasesTable.rows.length > 0) {\n      output.appendNode(\n        new DocHeading({\n          configuration: this._tsdocConfiguration,\n          title: 'Type Aliases',\n        }),\n      );\n      output.appendNode(typeAliasesTable);\n    }\n  }\n\n  /**\n   * GENERATE PAGE: CLASS\n   */\n  private _writeClassTables(output: DocSection, apiClass: ApiClass): void {\n    const postApiMembers: ApiItem[] = [];\n\n    for (const apiMember of apiClass.members) {\n      switch (apiMember.kind) {\n        case ApiItemKind.Constructor:\n        case ApiItemKind.Method:\n        case ApiItemKind.Property:\n          postApiMembers.push(apiMember);\n          break;\n      }\n    }\n\n    if (postApiMembers.length > 0) {\n      postApiMembers.forEach(postApiMember =>\n        this._writeApiItemPage(postApiMember, output),\n      );\n    }\n  }\n\n  /**\n   * GENERATE PAGE: ENUM\n   */\n  private _writeEnumTables(output: DocSection, apiEnum: ApiEnum): void {\n    const configuration: TSDocConfiguration = this._tsdocConfiguration;\n\n    const enumMembersTable: DocTable = new DocTable({\n      configuration,\n      headerTitles: ['Member', 'Value', 'Description'],\n    });\n\n    for (const apiEnumMember of apiEnum.members) {\n      enumMembersTable.addRow(\n        new DocTableRow({ configuration }, [\n          new DocTableCell({ configuration }, [\n            new DocParagraph({ configuration }, [\n              new DocPlainText({\n                configuration,\n                text: Utilities.getConciseSignature(apiEnumMember),\n              }),\n            ]),\n          ]),\n\n          new DocTableCell({ configuration }, [\n            new DocParagraph({ configuration }, [\n              new DocCodeSpan({\n                configuration,\n                code: apiEnumMember.initializerExcerpt?.text || '',\n              }),\n            ]),\n          ]),\n\n          this._createDescriptionCell(apiEnumMember),\n        ]),\n      );\n    }\n\n    if (enumMembersTable.rows.length > 0) {\n      output.appendNode(\n        new DocHeading({\n          configuration: this._tsdocConfiguration,\n          title: 'Enumeration Members',\n        }),\n      );\n      output.appendNode(enumMembersTable);\n    }\n  }\n\n  /**\n   * GENERATE PAGE: INTERFACE\n   */\n  private _writeInterfaceTables(\n    output: DocSection,\n    apiClass: ApiInterface,\n  ): void {\n    const postApiMembers: ApiItem[] = [];\n\n    for (const apiMember of apiClass.members) {\n      switch (apiMember.kind) {\n        case ApiItemKind.ConstructSignature:\n        case ApiItemKind.MethodSignature:\n        case ApiItemKind.PropertySignature:\n          postApiMembers.push(apiMember);\n          break;\n      }\n    }\n\n    if (postApiMembers.length > 0) {\n      postApiMembers.forEach(postApiItem =>\n        this._writeApiItemPage(postApiItem, output),\n      );\n    }\n  }\n\n  /**\n   * GENERATE PAGE: FUNCTION-LIKE\n   */\n  private _writeParameterTables(\n    output: DocSection,\n    apiParameterListMixin: ApiParameterListMixin,\n  ): void {\n    const configuration: TSDocConfiguration = this._tsdocConfiguration;\n\n    const parametersTable: DocTable = new DocTable({\n      configuration,\n      headerTitles: ['Parameter', 'Type', 'Description'],\n    });\n    for (const apiParameter of apiParameterListMixin.parameters) {\n      const parameterDescription: DocSection = new DocSection({\n        configuration,\n      });\n\n      if (apiParameter.isOptional) {\n        parameterDescription.appendNodesInParagraph([\n          new DocEmphasisSpan({ configuration, italic: true }, [\n            new DocPlainText({ configuration, text: '(Optional)' }),\n          ]),\n          new DocPlainText({ configuration, text: ' ' }),\n        ]);\n      }\n\n      if (apiParameter.tsdocParamBlock) {\n        this._appendAndMergeSection(\n          parameterDescription,\n          apiParameter.tsdocParamBlock.content,\n        );\n      }\n\n      parametersTable.addRow(\n        new DocTableRow({ configuration }, [\n          new DocTableCell({ configuration }, [\n            new DocParagraph({ configuration }, [\n              new DocPlainText({ configuration, text: apiParameter.name }),\n            ]),\n          ]),\n          new DocTableCell({ configuration }, [\n            this._createParagraphForTypeExcerpt(\n              apiParameter.parameterTypeExcerpt,\n            ),\n          ]),\n          new DocTableCell({ configuration }, parameterDescription.nodes),\n        ]),\n      );\n    }\n\n    if (parametersTable.rows.length > 0) {\n      output.appendNode(\n        new DocHeading({\n          configuration: this._tsdocConfiguration,\n          title: 'Parameters',\n          level: 3,\n        }),\n      );\n      output.appendNode(parametersTable);\n    }\n\n    if (ApiReturnTypeMixin.isBaseClassOf(apiParameterListMixin)) {\n      const returnTypeExcerpt: Excerpt =\n        apiParameterListMixin.returnTypeExcerpt;\n      output.appendNode(\n        new DocParagraph({ configuration }, [\n          new DocEmphasisSpan({ configuration, bold: true }, [\n            new DocPlainText({ configuration, text: 'Returns:' }),\n          ]),\n        ]),\n      );\n\n      output.appendNode(this._createParagraphForTypeExcerpt(returnTypeExcerpt));\n\n      if (apiParameterListMixin instanceof ApiDocumentedItem) {\n        if (\n          apiParameterListMixin.tsdocComment &&\n          apiParameterListMixin.tsdocComment.returnsBlock\n        ) {\n          this._appendSection(\n            output,\n            apiParameterListMixin.tsdocComment.returnsBlock.content,\n          );\n        }\n      }\n    }\n  }\n\n  private _createParagraphForTypeExcerpt(excerpt: Excerpt): DocParagraph {\n    const configuration: TSDocConfiguration = this._tsdocConfiguration;\n\n    const paragraph: DocParagraph = new DocParagraph({ configuration });\n\n    if (!excerpt.text.trim()) {\n      paragraph.appendNode(\n        new DocPlainText({ configuration, text: '(not declared)' }),\n      );\n    } else this._appendExcerptWithHyperlinks(paragraph, excerpt);\n\n    return paragraph;\n  }\n\n  private _appendExcerptWithHyperlinks(\n    docNodeContainer: DocNodeContainer,\n    excerpt: Excerpt,\n  ): void {\n    for (const token of excerpt.spannedTokens)\n      this._appendExcerptTokenWithHyperlinks(docNodeContainer, token);\n  }\n\n  private _appendExcerptTokenWithHyperlinks(\n    docNodeContainer: DocNodeContainer,\n    token: ExcerptToken,\n  ): void {\n    const configuration: TSDocConfiguration = this._tsdocConfiguration;\n\n    // Markdown doesn't provide a standardized syntax for hyperlinks inside code spans, so we will render\n    // the type expression as DocPlainText.  Instead of creating multiple DocParagraphs, we can simply\n    // discard any newlines and let the renderer do normal word-wrapping.\n    const unwrappedTokenText: string = token.text.replace(/[\\r\\n]+/g, ' ');\n\n    // If it's hyperlinkable, then append a DocLinkTag\n    if (token.kind === ExcerptTokenKind.Reference && token.canonicalReference) {\n      const apiItemResult: IResolveDeclarationReferenceResult =\n        this._apiModel.resolveDeclarationReference(\n          token.canonicalReference,\n          undefined,\n        );\n\n      if (apiItemResult.resolvedApiItem) {\n        docNodeContainer.appendNode(\n          new DocLinkTag({\n            configuration,\n            tagName: '@link',\n            linkText: unwrappedTokenText,\n            urlDestination: this._getLinkFilenameForApiItem(\n              apiItemResult.resolvedApiItem,\n            ),\n          }),\n        );\n        return;\n      }\n    }\n\n    // Otherwise append non-hyperlinked text\n    docNodeContainer.appendNode(\n      new DocPlainText({ configuration, text: unwrappedTokenText }),\n    );\n  }\n\n  private _createTitleCell(apiItem: ApiItem): DocTableCell {\n    const configuration: TSDocConfiguration = this._tsdocConfiguration;\n\n    let linkText: string = Utilities.getConciseSignature(apiItem);\n    if (ApiOptionalMixin.isBaseClassOf(apiItem) && apiItem.isOptional)\n      linkText += '?';\n\n    return new DocTableCell({ configuration }, [\n      new DocParagraph({ configuration }, [\n        new DocLinkTag({\n          configuration,\n          tagName: '@link',\n          linkText: linkText,\n          urlDestination: this._getLinkFilenameForApiItem(apiItem),\n        }),\n      ]),\n    ]);\n  }\n\n  /**\n   * This generates a DocTableCell for an ApiItem including the summary section and \"(BETA)\" annotation.\n   *\n   * @remarks\n   * We mostly assume that the input is an ApiDocumentedItem, but it's easier to perform this as a runtime\n   * check than to have each caller perform a type cast.\n   */\n  private _createDescriptionCell(apiItem: ApiItem): DocTableCell {\n    const configuration: TSDocConfiguration = this._tsdocConfiguration;\n\n    const section: DocSection = new DocSection({ configuration });\n\n    if (ApiReleaseTagMixin.isBaseClassOf(apiItem)) {\n      if (apiItem.releaseTag === ReleaseTag.Beta) {\n        section.appendNodesInParagraph([\n          new DocEmphasisSpan({ configuration, bold: true, italic: true }, [\n            new DocPlainText({ configuration, text: '(BETA)' }),\n          ]),\n          new DocPlainText({ configuration, text: ' ' }),\n        ]);\n      }\n    }\n\n    if (ApiOptionalMixin.isBaseClassOf(apiItem) && apiItem.isOptional) {\n      section.appendNodesInParagraph([\n        new DocEmphasisSpan({ configuration, italic: true }, [\n          new DocPlainText({ configuration, text: '(Optional)' }),\n        ]),\n        new DocPlainText({ configuration, text: ' ' }),\n      ]);\n    }\n\n    if (apiItem instanceof ApiDocumentedItem) {\n      if (apiItem.tsdocComment !== undefined) {\n        this._appendAndMergeSection(\n          section,\n          apiItem.tsdocComment.summarySection,\n        );\n      }\n    }\n\n    return new DocTableCell({ configuration }, section.nodes);\n  }\n\n  private _writeBreadcrumb(output: DocSection, apiItem: ApiItem): void {\n    const breadcrumbDivider = [\n      new DocPlainText({\n        configuration: this._tsdocConfiguration,\n        text: ' > ',\n      }),\n    ];\n\n    for (const hierarchyItem of apiItem.getHierarchy()) {\n      const isFirst = hierarchyItem.kind === ApiItemKind.Package;\n\n      switch (hierarchyItem.kind) {\n        case ApiItemKind.Model:\n        case ApiItemKind.EntryPoint:\n          // We don't show the model as part of the breadcrumb because it is the root-level container.\n          // We don't show the entry point because today API Extractor doesn't support multiple entry points;\n          // this may change in the future.\n          break;\n        default:\n          output.appendNodesInParagraph([\n            ...(isFirst ? [] : breadcrumbDivider),\n            new DocLinkTag({\n              configuration: this._tsdocConfiguration,\n              tagName: '@link',\n              linkText: hierarchyItem.displayName,\n              urlDestination: this._getLinkFilenameForApiItem(hierarchyItem),\n            }),\n          ]);\n      }\n    }\n  }\n\n  private _writeBetaWarning(output: DocSection): void {\n    const configuration: TSDocConfiguration = this._tsdocConfiguration;\n    const betaWarning: string =\n      'This API is provided as a preview for developers and may change' +\n      ' based on feedback that we receive.  Do not use this API in a production environment.';\n    output.appendNode(\n      new DocNoteBox({ configuration }, [\n        new DocParagraph({ configuration }, [\n          new DocPlainText({ configuration, text: betaWarning }),\n        ]),\n      ]),\n    );\n  }\n\n  private _appendSection(output: DocSection, docSection: DocSection): void {\n    for (const node of docSection.nodes) output.appendNode(node);\n  }\n\n  private _appendAndMergeSection(\n    output: DocSection,\n    docSection: DocSection,\n  ): void {\n    let firstNode: boolean = true;\n    for (const node of docSection.nodes) {\n      if (firstNode) {\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n        if (node.kind === DocNodeKind.Paragraph) {\n          output.appendNodesInParagraph(node.getChildNodes());\n          firstNode = false;\n          continue;\n        }\n      }\n      firstNode = false;\n\n      output.appendNode(node);\n    }\n  }\n\n  private _getFilenameForApiItem(\n    apiItem: ApiItem,\n    nestedWhenSameName: boolean = false,\n  ): string {\n    if (apiItem.kind === ApiItemKind.Model) {\n      // this file will be ignored, we don't like the old index file.\n      return 'ignored.md';\n    }\n\n    const apiDocumentedItem = apiItem as ApiDocumentedItem;\n\n    if (apiDocumentedItem.tsdocComment) {\n      const breadcrumb = apiDocumentedItem.tsdocComment.customBlocks.find(\n        block => block.blockTag.tagName === '@breadcrumb',\n      );\n\n      if (breadcrumb) {\n        const breadcrumbContent = breadcrumb.content\n          .getChildNodes()\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n          .filter(block => block.kind === DocNodeKind.Paragraph)\n          // @ts-ignore\n          .reduce((acc, block) => [...acc, ...block.getChildNodes()], [])\n          // @ts-ignore\n          .filter(block => block.kind === DocNodeKind.PlainText)\n          .map((plainText: DocPlainText) => plainText.text)\n          .join('');\n\n        const breadcrumbs = breadcrumbContent\n          .split('/')\n          .map(section => section.trimLeft().trimRight());\n\n        const safeName = CustomUtilities.getSafeFilenameForNameWithCase(\n          apiItem.displayName,\n        );\n\n        if (breadcrumbs.length === 0) return safeName + '.md';\n\n        const filename =\n          !nestedWhenSameName &&\n          breadcrumbs[breadcrumbs.length - 1] === safeName\n            ? ''\n            : safeName + '.md';\n\n        if (!filename) return breadcrumbs.join('/') + '.md';\n\n        return [...breadcrumbs, filename].join('/');\n      }\n    }\n\n    let baseName: string = '';\n\n    for (const hierarchyItem of apiItem.getHierarchy()) {\n      // For overloaded methods, add a suffix such as \"MyClass.myMethod_2\".\n      let qualifiedName: string =\n        CustomUtilities.getSafeFilenameForNameWithCase(\n          hierarchyItem.displayName,\n        );\n\n      if (ApiParameterListMixin.isBaseClassOf(hierarchyItem)) {\n        if (hierarchyItem.overloadIndex > 1) {\n          // Subtract one for compatibility with earlier releases of API Documenter.\n          // (This will get revamped when we fix GitHub issue #1308)\n          qualifiedName += `_${hierarchyItem.overloadIndex - 1}`;\n        }\n      }\n\n      switch (hierarchyItem.kind) {\n        case ApiItemKind.Model:\n        case ApiItemKind.EntryPoint:\n        case ApiItemKind.EnumMember:\n        case ApiItemKind.Package:\n          break;\n        default:\n          baseName = baseName ? baseName + '.' + qualifiedName : qualifiedName;\n      }\n    }\n\n    // when we don't have name, usually is the package documentation\n    if (!baseName) return 'Introduction.md';\n\n    if (baseName.startsWith('___')) {\n      // ignore files from deepkit\n      return 'ignored.md';\n    }\n\n    return baseName + '.md';\n  }\n\n  private _getLinkFilenameForApiItem(apiItem: ApiItem): string {\n    return (\n      '/docs/api/' +\n      this._getFilenameForApiItem(apiItem)\n        .replace(/\\.md/g, '')\n        .replace(/ /g, '%20')\n    );\n  }\n\n  private _deleteOldOutputFiles(): void {\n    console.log('Deleting old output from ' + this._outputFolder);\n    FileSystem.ensureEmptyFolder(this._outputFolder);\n  }\n}\n"
  },
  {
    "path": "scripts/libs/CustomUtilities.ts",
    "content": "import { ApiItem, ApiParameterListMixin } from '@microsoft/api-extractor-model';\n\nexport class CustomUtilities {\n  private static readonly _badFilenameCharsRegExp: RegExp = /[^a-z0-9_\\-.]/gi;\n\n  /**\n   * Generates a concise signature for a function.  Example: \"getArea(width, height)\"\n   */\n  public static getConciseSignature(apiItem: ApiItem): string {\n    if (ApiParameterListMixin.isBaseClassOf(apiItem)) {\n      return (\n        apiItem.displayName +\n        '(' +\n        apiItem.parameters.map(x => x.name).join(', ') +\n        ')'\n      );\n    }\n    return apiItem.displayName;\n  }\n\n  /**\n   * Converts bad filename characters to underscores.\n   */\n  public static getSafeFilenameForName(name: string): string {\n    // TODO: This can introduce naming collisions.\n    // We will fix that as part of https://github.com/microsoft/rushstack/issues/1308\n    return name\n      .replace(CustomUtilities._badFilenameCharsRegExp, '_')\n      .toLowerCase();\n  }\n\n  /**\n   * Converts bad filename characters to underscores.\n   */\n  public static getSafeFilenameForNameWithCase(name: string): string {\n    // TODO: This can introduce naming collisions.\n    // We will fix that as part of https://github.com/microsoft/rushstack/issues/1308\n    return name.replace(CustomUtilities._badFilenameCharsRegExp, '_');\n  }\n}\n"
  },
  {
    "path": "scripts/libs/MarkdownEmitter.ts",
    "content": "import { CustomMarkdownEmitter } from '@microsoft/api-documenter/lib/markdown/CustomMarkdownEmitter';\nimport type { IMarkdownEmitterContext } from '@microsoft/api-documenter/lib/markdown/MarkdownEmitter';\nimport { IndentedWriter } from '@microsoft/api-documenter/lib/utils/IndentedWriter';\n\nexport class MarkdownEmitter extends CustomMarkdownEmitter {\n  protected override writePlainText(\n    text: string,\n    context: IMarkdownEmitterContext,\n  ): void {\n    const writer: IndentedWriter = context.writer;\n\n    // split out the [ leading whitespace, content, trailing whitespace ]\n    const parts: string[] = text.match(/^(\\s*)(.*?)(\\s*)$/) || [];\n\n    writer.write(parts[1]); // write leading whitespace\n\n    const middle: string = parts[2];\n\n    if (middle !== '') {\n      switch (writer.peekLastCharacter()) {\n        case '':\n        case '\\n':\n        case ' ':\n        case '[':\n        case '>':\n          // okay to put a symbol\n          break;\n        default:\n          // This is no problem:        \"**one** *two* **three**\"\n          // But this is trouble:       \"**one***two***three**\"\n          // The most general solution: \"**one**<!-- -->*two*<!-- -->**three**\"\n          // but the solution above breaks docusaurus, so, I changed to space\n          writer.write(' ');\n          break;\n      }\n\n      writer.write(this.getEscapedText(middle));\n    }\n\n    writer.write(parts[3]); // write trailing whitespace\n  }\n}\n"
  },
  {
    "path": "scripts/models/apidoc.types.ts",
    "content": "export interface APIDoc {\n  metadata: Metadata;\n  kind: string;\n  canonicalReference: string;\n  docComment: string;\n  name: string;\n  members: APIDocMember[];\n}\n\nexport interface APIDocMember {\n  kind: string;\n  canonicalReference: string;\n  name: string;\n  members: PurpleMember[];\n}\n\nexport interface PurpleMember {\n  kind: PurpleKind;\n  canonicalReference: string;\n  docComment: string;\n  excerptTokens: ExcerptToken[];\n  releaseTag: ReleaseTag;\n  typeParameters?: TypeParameter[];\n  name: string;\n  members?: FluffyMember[];\n  extendsTokenRanges?: any[];\n  implementsTokenRanges?: TokenRange[];\n  typeTokenRange?: TokenRange;\n  returnTypeTokenRange?: TokenRange;\n  overloadIndex?: number;\n  parameters?: Parameter[];\n  variableTypeTokenRange?: TokenRange;\n  extendsTokenRange?: TokenRange;\n}\n\nexport interface ExcerptToken {\n  kind: ExcerptTokenKind;\n  text: string;\n  canonicalReference?: string;\n}\n\nexport enum ExcerptTokenKind {\n  Content = 'Content',\n  Reference = 'Reference',\n}\n\nexport interface TokenRange {\n  startIndex: number;\n  endIndex: number;\n}\n\nexport enum PurpleKind {\n  Class = 'Class',\n  Function = 'Function',\n  Interface = 'Interface',\n  TypeAlias = 'TypeAlias',\n  Variable = 'Variable',\n}\n\nexport interface FluffyMember {\n  kind: FluffyKind;\n  canonicalReference: string;\n  docComment: string;\n  excerptTokens: ExcerptToken[];\n  isOptional?: boolean;\n  returnTypeTokenRange?: TokenRange;\n  releaseTag: ReleaseTag;\n  overloadIndex?: number;\n  parameters?: Parameter[];\n  name?: string;\n  propertyTypeTokenRange?: TokenRange;\n  isStatic?: boolean;\n  typeParameters?: TypeParameter[];\n}\n\nexport enum FluffyKind {\n  Constructor = 'Constructor',\n  Method = 'Method',\n  MethodSignature = 'MethodSignature',\n  Property = 'Property',\n  PropertySignature = 'PropertySignature',\n}\n\nexport interface Parameter {\n  parameterName: string;\n  parameterTypeTokenRange: TokenRange;\n  isOptional: boolean;\n}\n\nexport enum ReleaseTag {\n  Public = 'Public',\n}\n\nexport interface TypeParameter {\n  typeParameterName: TypeParameterName;\n  constraintTokenRange: TokenRange;\n  defaultTypeTokenRange: TokenRange;\n}\n\nexport enum TypeParameterName {\n  T = 'T',\n  TApp = 'TApp',\n  TCallback = 'TCallback',\n  TContext = 'TContext',\n  TEvent = 'TEvent',\n  TResponse = 'TResponse',\n  TReturn = 'TReturn',\n  TStream = 'TStream',\n}\n\nexport interface Metadata {\n  toolPackage: string;\n  toolVersion: string;\n  schemaVersion: number;\n  oldestForwardsCompatibleVersion: number;\n  tsdocConfig: TsdocConfig;\n}\n\nexport interface TsdocConfig {\n  $schema: string;\n  noStandardTags: boolean;\n  tagDefinitions: TagDefinition[];\n  supportForTags: { [key: string]: boolean };\n}\n\nexport interface TagDefinition {\n  tagName: string;\n  syntaxKind: SyntaxKind;\n  allowMultiple?: boolean;\n}\n\nexport enum SyntaxKind {\n  Block = 'block',\n  Inline = 'inline',\n  Modifier = 'modifier',\n}\n"
  },
  {
    "path": "scripts/parse-docs.ts",
    "content": "import { resolve } from 'path';\nimport { Extractor, ExtractorConfig } from '@microsoft/api-extractor';\n\nconst apiExtractConfig = resolve('./api-extractor.json');\n\nfunction build(): void {\n  const config = ExtractorConfig.loadFileAndPrepare(apiExtractConfig);\n\n  const extractorResult = Extractor.invoke(config, {\n    localBuild: true,\n  });\n\n  if (!extractorResult.succeeded) {\n    console.error(\n      `API Extractor completed with ${extractorResult.errorCount} errors` +\n        ` and ${extractorResult.warningCount} warnings`,\n    );\n    process.exitCode = 1;\n  }\n\n  console.log('API Extractor completed successfully');\n}\n\nbuild();\n"
  },
  {
    "path": "src/@types/binary-settings.ts",
    "content": "/**\n * The interface representing the binary settings implementation by function\n *\n * @breadcrumb Types / BinarySettings\n * @public\n */\nexport interface BinarySettingsFunction {\n  /**\n   * This property can be a function that receives the response headers and returns whether that response should be encoded as binary.\n   * Otherwise, you can specify not to treat any response as binary by putting `false` in this property.\n   *\n   * @remarks Setting this property prevents the `contentTypes` and `contentEncodings` properties from being used.\n   */\n  isBinary:\n    | ((headers: Record<string, string | string[] | undefined>) => boolean)\n    | false;\n}\n\n/**\n * The interface representing the binary settings implementation by looking inside the headers\n *\n * @breadcrumb Types / BinarySettings\n * @public\n */\nexport interface BinarySettingsContentHeaders {\n  /**\n   * The list of content types that will be treated as binary\n   */\n  contentTypes: string[];\n\n  /**\n   * The list of content encodings that will be treated as binary\n   */\n  contentEncodings: string[];\n}\n\n/**\n * The interface representing the settings for whether the response should be treated as binary or not\n *\n * @remarks Encoded as binary means the response body will be converted to base64\n *\n * @breadcrumb Types / BinarySettings\n * @public\n */\nexport type BinarySettings =\n  | BinarySettingsFunction\n  | BinarySettingsContentHeaders;\n"
  },
  {
    "path": "src/@types/digital-ocean/digital-ocean-http-event.ts",
    "content": "//#region Imports\n\nimport type { SingleValueHeaders } from '../headers';\n\n//#endregion\n\n/**\n * The interface to represents the values of args send when someone calls a function using HTTP Endpoint.\n * To be able to receive this event, inside your `project.yml`, instead of `web: true` change to `web: 'raw'`.\n *\n * {@link https://www.digitalocean.com/community/questions/digitalocean-functions-how-to-differentiate-query-params-from-body-params | Reference}\n *\n * @public\n * @breadcrumb Types / Digital Ocean / DigitalOceanHttpEvent\n */\nexport interface DigitalOceanHttpEvent {\n  /**\n   * The HTTP Method of the request\n   */\n  __ow_method: string;\n\n  /**\n   * The query porams of the request\n   */\n  __ow_query: string;\n\n  /**\n   * The body of the request.\n   */\n  __ow_body?: string;\n\n  /**\n   * Indicates if body is base64 string\n   */\n  __ow_isBase64Encoded?: boolean;\n\n  /**\n   * The HTTP Headers of the request\n   */\n  __ow_headers: SingleValueHeaders;\n\n  /**\n   * The path in the request\n   */\n  __ow_path: string;\n}\n"
  },
  {
    "path": "src/@types/digital-ocean/digital-ocean-http-response.ts",
    "content": "//#region Imports\n\nimport type { SingleValueHeaders } from '../headers';\n\n//#endregion\n\n/**\n * The interface to represents the response of Digital Ocean Function.\n *\n * @public\n * @breadcrumb Types / Digital Ocean / DigitalOceanHttpResponse\n */\nexport interface DigitalOceanHttpResponse {\n  /**\n   * The HTTP Headers of the response\n   */\n  headers?: SingleValueHeaders;\n\n  /**\n   * The body of the response\n   */\n  body: unknown;\n\n  /**\n   * The HTTP Status code of the response\n   */\n  statusCode: number;\n}\n"
  },
  {
    "path": "src/@types/digital-ocean/index.ts",
    "content": "export * from './digital-ocean-http-event';\nexport * from './digital-ocean-http-response';\n"
  },
  {
    "path": "src/@types/headers.ts",
    "content": "/**\n * The record that represents the headers that doesn't have multiple values in the value\n *\n * @example\n * ```typescript\n * { 'Accept-Encoding': 'gzip, deflate, br' }\n * ```\n *\n * @breadcrumb Types\n * @public\n */\nexport type SingleValueHeaders = Record<string, string | undefined>;\n\n/**\n * The record that represents the headers that have multiple values in the value\n *\n * @example\n * ```typescript\n * { 'Accept-Encoding': ['gzip', 'deflate', 'br'] }\n * ```\n *\n * @breadcrumb Types\n * @public\n */\nexport type MultiValueHeaders = Record<string, string[] | undefined>;\n\n/**\n * The record that represents the headers that can both single or multiple values in the value\n *\n * @example\n * ```typescript\n * { 'Accept-Encoding': ['gzip', 'deflate', 'br'], 'Host': 'xyz.execute-api.us-east-1.amazonaws.com' }\n * ```\n *\n * @breadcrumb Types\n * @public\n */\nexport type BothValueHeaders = Record<string, string | string[] | undefined>;\n"
  },
  {
    "path": "src/@types/helpers.ts",
    "content": "/**\n * Removes 'optional' attributes from a type's properties\n *\n * @breadcrumb Types\n * @public\n */\nexport type Concrete<Type> = {\n  [Property in keyof Type]-?: Type[Property];\n};\n"
  },
  {
    "path": "src/@types/huawei/huawei-api-gateway-event.ts",
    "content": "//#region Imports\n\nimport type { BothValueHeaders } from '../index';\n\n//#endregion\n\n/**\n * The interface that represents the Api Gateway Event of Huawei when integrate with Function Graph of Event Type.\n * See more in {@link https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0102.html#functiongraph_02_0102__li5178638110137 | Reference}.\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiApiGatewayEvent\n */\nexport interface HuaweiApiGatewayEvent {\n  /**\n   * The body value with the content of this event serialized in JSON\n   */\n  body: string;\n\n  /**\n   * The headers of the request which this event represents\n   */\n  headers: BothValueHeaders;\n\n  /**\n   * The HTTP Method of the request which this event represents\n   */\n  httpMethod: string;\n\n  /**\n   * Tells if the body is base64 encoded\n   */\n  isBase64Encoded: boolean;\n\n  /**\n   * The path of the request which this event represents\n   */\n  path: string;\n\n  /**\n   * The path parameters of the request which this event represents\n   */\n  pathParameters: HuaweiRequestPathParameters;\n\n  /**\n   * The query strings of the request which this event represents\n   */\n  queryStringParameters: HuaweiRequestQueryStringParameters;\n\n  /**\n   * The request context with information about the stage, api and requestId\n   */\n  requestContext: HuaweiRequestContext;\n\n  /**\n   * It can have more properties that I could not discover yet\n   */\n  [key: string]: any;\n}\n\n/**\n * The path parameters of the request, usually is the name of the wildcard you create in FunctionGraph, such as /\\{proxy\\}.\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiApiGatewayEvent\n */\nexport type HuaweiRequestPathParameters = Record<string, string>;\n\n/**\n * The query strings of the request\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiApiGatewayEvent\n */\nexport type HuaweiRequestQueryStringParameters = Record<\n  string,\n  string | string[]\n>;\n\n/**\n * The interface that represents the values you can get inside request context.\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiApiGatewayEvent\n */\nexport interface HuaweiRequestContext {\n  /**\n   * The ID of your API inside Api Gateway\n   */\n  apiId: string;\n\n  /**\n   * The ID of this request\n   */\n  requestId: string;\n\n  /**\n   * The name of the stage running this Function Graph\n   */\n  stage: string;\n}\n"
  },
  {
    "path": "src/@types/huawei/huawei-api-gateway-response.ts",
    "content": "//#region Imports\n\nimport type { MultiValueHeaders } from '../headers';\n\n//#endregion\n\n/**\n * The interface that represents the Api Gateway Response of Huawei when integrate with Function Graph of Event Type.\n * See more in {@link https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0102.html#functiongraph_02_0102__li5178638110137 | Reference}.\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiApiGatewayResponse\n */\nexport interface HuaweiApiGatewayResponse {\n  /**\n   * Tells if the body was encoded as base64\n   */\n  isBase64Encoded: boolean;\n\n  /**\n   * The HTTP Status code of this response\n   */\n  statusCode: number;\n\n  /**\n   * The headers sent with this response\n   */\n  headers: MultiValueHeaders;\n\n  /**\n   * The body value with the content of this response serialized in JSON\n   */\n  body: string;\n}\n"
  },
  {
    "path": "src/@types/huawei/huawei-context.ts",
    "content": "/**\n * The return value of {@link HuaweiContext} getRequestID\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetRequestIDSecondsReturn = string;\n\n/**\n * The return value of {@link HuaweiContext} getRemainingTimeInMilliSeconds\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetRemainingTimeInMilliSecondsReturn = number;\n\n/**\n * The return value of {@link HuaweiContext} getAccessKey\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetAccessKeyReturn = string;\n\n/**\n * The return value of {@link HuaweiContext} getSecretKey\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetSecretKeyReturn = string;\n\n/**\n * The parameters of the method {@link HuaweiContext} getUserData\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetUserDataKeyParameter = string;\n\n/**\n * The return value of {@link HuaweiContext} getUserData\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetUserDataReturn = any;\n\n/**\n * The return value of {@link HuaweiContext} getFunctionName\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetFunctionNameReturn = string;\n\n/**\n * The return value of {@link HuaweiContext} getRunningTimeInSeconds\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetRunningTimeInSecondsReturn = number;\n\n/**\n * The return value of {@link HuaweiContext} getVersion\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetVersionReturn = string;\n\n/**\n * The return value of {@link HuaweiContext} getMemorySize\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetMemorySizeReturn = number;\n\n/**\n * The return value of {@link HuaweiContext} getCPUNumber\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetCPUNumberReturn = number;\n\n/**\n * The return value of {@link HuaweiContext} getProjectID\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetProjectIdReturn = number;\n\n/**\n * The return value of {@link HuaweiContext} getPackage\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetPackageReturn = string;\n\n/**\n * The return value of {@link HuaweiContext} getToken\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetTokenReturn = string;\n\n/**\n * The return value of {@link HuaweiContext} getLogger\n *\n * Is the instance of logger that can be used to send logs to\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport type GetLoggerReturn = {\n  info(message: string): void;\n};\n\n/**\n * The interface that represents methods sent by huawei to get information about the function graph.\n * See more in {@link https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0410.html#section1 | Context Methods}\n *\n * @public\n * @breadcrumb Types / Huawei / HuaweiContext\n */\nexport interface HuaweiContext {\n  /**\n   * Obtains a request ID.\n   */\n  getRequestID(): GetRequestIDSecondsReturn;\n\n  /**\n   * Obtains the remaining running time of a function.\n   */\n  getRemainingTimeInMilliSeconds(): GetRemainingTimeInMilliSecondsReturn;\n\n  /**\n   * Obtains the AK (valid for 24 hours) of an agency. If you use this method, you need to configure an agency for the function.\n   */\n  getAccessKey(): GetAccessKeyReturn;\n\n  /**\n   * Obtains the SK (valid for 24 hours) of an agency. If you use this method, you need to configure an agency for the function.\n   */\n  getSecretKey(): GetSecretKeyReturn;\n\n  /**\n   * Uses keys to obtain the values passed by environment variables.\n   *\n   * @param key - The key to get environment variables values\n   */\n  getUserData(key: GetUserDataKeyParameter): GetUserDataReturn;\n\n  /**\n   * Obtains the name of a function.\n   */\n  getFunctionName(): GetFunctionNameReturn;\n\n  /**\n   * Obtains the timeout of a function.\n   */\n  getRunningTimeInSeconds(): GetRunningTimeInSecondsReturn;\n\n  /**\n   * Obtains the version of a function.\n   */\n  getVersion(): GetVersionReturn;\n\n  /**\n   * Obtains the allocated memory.\n   */\n  getMemorySize(): GetMemorySizeReturn;\n\n  /**\n   * Number of CPU millicores used by the function (1 core = 1000 millicores).\n   *\n   * The value of this field is proportional to that of MemorySize. By default, 100 CPU millicores are required for 128 MB memory. The number of CPU millicores is calculated as follows: Memory/128 x 100 + 200 (basic CPU millicores).\n   */\n  getCPUNumber(): GetCPUNumberReturn;\n\n  /**\n   * Obtains a project ID.\n   */\n  getProjectID(): GetProjectIdReturn;\n\n  /**\n   * Obtains a function group, that is, an app.\n   */\n  getPackage(): GetPackageReturn;\n\n  /**\n   * Obtains the token (valid for 24 hours) of an agency. If you use this method, you need to configure an agency for the function.\n   */\n  getToken(): GetTokenReturn;\n\n  /**\n   * Obtains the logger method provided by the context and returns a log output class. Logs are output in the format of Time-Request ID-Content by using the info method.\n   *\n   * For example, use the info method to output logs:\n   *\n   * @example\n   * ```typescript\n   * logg = context.getLogger()\n   *\n   * logg.info(\"hello\")\n   * ```\n   */\n  getLogger(): GetLoggerReturn;\n}\n"
  },
  {
    "path": "src/@types/huawei/index.ts",
    "content": "export * from './huawei-context';\nexport * from './huawei-api-gateway-event';\nexport * from './huawei-api-gateway-response';\n"
  },
  {
    "path": "src/@types/index.ts",
    "content": "export * from './binary-settings';\nexport * from './headers';\nexport * from './helpers';\n"
  },
  {
    "path": "src/adapters/apollo-server/apollo-server-mutation.adapter.ts",
    "content": "//#region Imports\n\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  GetResponseAdapterProps,\n  OnErrorProps,\n} from '../../contracts';\nimport {\n  type ILogger,\n  getDefaultIfUndefined,\n  getEventBodyAsBuffer,\n} from '../../core';\n\n//#endregion\n\n/**\n * The options for {@link ApolloServerMutationAdapter}\n *\n * @breadcrumb Adapters / Apollo Server / ApolloServerMutationAdapter\n * @public\n */\nexport type ApolloServerMutationAdapterOptions = {\n  /**\n   * Specify the name of mutation that will be called when an event was received\n   */\n  mutationName: string;\n\n  /**\n   * Specify the mutation result schema.\n   * Use this to customize the behavior when you need to return a specific object to be handled by the Adapter, like SQS with Batch Mode.\n   *\n   * @defaultValue `{ __typename }`\n   */\n  mutationResultQuery?: string;\n};\n\n/**\n * The adapter that wraps another adapter to force a transformation of the event data as a mutation to Apollo Server be able to handle.\n *\n * @breadcrumb Adapters / Apollo Server / ApolloServerMutationAdapter\n * @public\n */\nexport class ApolloServerMutationAdapter<TEvent, TContext, TResponse>\n  implements AdapterContract<TEvent, TContext, TResponse>\n{\n  //#region Constructor\n\n  /**\n   * The default constructor\n   */\n  constructor(\n    protected readonly baseAdapter: AdapterContract<\n      TEvent,\n      TContext,\n      TResponse\n    >,\n    protected readonly options: ApolloServerMutationAdapterOptions,\n  ) {}\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public canHandle(event: unknown, context: TContext, log: ILogger): boolean {\n    return this.baseAdapter.canHandle(event, context, log);\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getAdapterName(): string {\n    return this.baseAdapter.getAdapterName() + 'Mutation';\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getRequest(\n    event: TEvent,\n    context: TContext,\n    log: ILogger,\n  ): AdapterRequest {\n    const request = this.baseAdapter.getRequest(event, context, log);\n\n    request.method = 'POST';\n\n    const operationName = this.options.mutationName;\n    const mutationResultQuery = getDefaultIfUndefined(\n      this.options.mutationResultQuery,\n      '{ __typename }',\n    );\n\n    const mutationBody = JSON.stringify({\n      operationName,\n      query: `mutation ${operationName} ($event: String) { ${operationName} (event: $event) ${mutationResultQuery} }`,\n      variables: {\n        event: request.body?.toString() || '',\n      },\n    });\n\n    const [buffer, contentLength] = getEventBodyAsBuffer(mutationBody, false);\n\n    request.body = buffer;\n    request.headers['content-type'] = 'application/json';\n    request.headers['content-length'] = String(contentLength);\n\n    return request;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getResponse(props: GetResponseAdapterProps<TEvent>): TResponse {\n    const { data, errors } = JSON.parse(props.body);\n\n    if (!errors) {\n      return this.baseAdapter.getResponse({\n        ...props,\n        body: JSON.stringify(data[this.options.mutationName]),\n      });\n    }\n\n    // when error happens, is the responsability of base adapter\n    // to deal with error status code.\n    return this.baseAdapter.getResponse(props);\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public onErrorWhileForwarding(props: OnErrorProps<TEvent, TResponse>): void {\n    return this.baseAdapter.onErrorWhileForwarding(props);\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/apollo-server/index.ts",
    "content": "export * from './apollo-server-mutation.adapter';\n"
  },
  {
    "path": "src/adapters/aws/alb.adapter.ts",
    "content": "//#region Imports\n\nimport type { ALBEvent, ALBResult, Context } from 'aws-lambda';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  GetResponseAdapterProps,\n  OnErrorProps,\n} from '../../contracts';\nimport {\n  type StripBasePathFn,\n  buildStripBasePath,\n  getEventBodyAsBuffer,\n  getFlattenedHeadersMap,\n  getMultiValueHeadersMap,\n  getPathWithQueryStringParams,\n} from '../../core';\n\n//#endregion\n\n/**\n * The options to customize the {@link AlbAdapter}\n *\n * @breadcrumb Adapters / AWS / AlbAdapter\n * @public\n */\nexport interface AlbAdapterOptions {\n  /**\n   * Strip base path for custom domains\n   *\n   * @defaultValue ''\n   */\n  stripBasePath?: string;\n}\n\n/**\n * The adapter to handle requests from AWS ALB\n *\n * @example\n * ```typescript\n * const stripBasePath = '/any/custom/base/path'; // default ''\n * const adapter = new AlbAdapter({ stripBasePath });\n * ```\n *\n * {@link https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html | Event Reference}\n *\n * @breadcrumb Adapters / AWS / AlbAdapter\n * @public\n */\nexport class AlbAdapter\n  implements AdapterContract<ALBEvent, Context, ALBResult>\n{\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link AlbAdapter}\n   */\n  constructor(protected readonly options?: AlbAdapterOptions) {\n    this.stripPathFn = buildStripBasePath(this.options?.stripBasePath);\n  }\n\n  //#endregion\n\n  //#region Protected Properties\n\n  /**\n   * Strip base path function\n   */\n  protected stripPathFn: StripBasePathFn;\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getAdapterName(): string {\n    return AlbAdapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public canHandle(event: unknown): event is ALBEvent {\n    const albEvent = event as Partial<ALBEvent>;\n\n    return !!(albEvent?.requestContext && albEvent.requestContext.elb);\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getRequest(event: ALBEvent): AdapterRequest {\n    const method = event.httpMethod;\n    const path = this.getPathFromEvent(event);\n\n    const headers = event.multiValueHeaders\n      ? getFlattenedHeadersMap(event.multiValueHeaders, ',', true)\n      : event.headers!;\n\n    let body: Buffer | undefined;\n\n    if (event.body) {\n      const [bufferBody, contentLength] = getEventBodyAsBuffer(\n        event.body,\n        event.isBase64Encoded,\n      );\n\n      body = bufferBody;\n      headers['content-length'] = String(contentLength);\n    }\n\n    let remoteAddress = '';\n\n    // ref: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/x-forwarded-headers.html#x-forwarded-for\n    if (headers['x-forwarded-for']) remoteAddress = headers['x-forwarded-for'];\n\n    return {\n      method,\n      headers,\n      body,\n      remoteAddress,\n      path,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getResponse({\n    event,\n    headers: responseHeaders,\n    body,\n    isBase64Encoded,\n    statusCode,\n  }: GetResponseAdapterProps<ALBEvent>): ALBResult {\n    const multiValueHeaders = !event.headers\n      ? getMultiValueHeadersMap(responseHeaders)\n      : undefined;\n\n    const headers = event.headers\n      ? getFlattenedHeadersMap(responseHeaders)\n      : undefined;\n\n    if (headers && headers['transfer-encoding'] === 'chunked')\n      delete headers['transfer-encoding'];\n\n    if (\n      multiValueHeaders &&\n      multiValueHeaders['transfer-encoding']?.includes('chunked')\n    )\n      delete multiValueHeaders['transfer-encoding'];\n\n    return {\n      statusCode,\n      body,\n      headers,\n      multiValueHeaders,\n      isBase64Encoded,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public onErrorWhileForwarding({\n    error,\n    delegatedResolver,\n    respondWithErrors,\n    event,\n    log,\n  }: OnErrorProps<ALBEvent, ALBResult>): void {\n    const body = respondWithErrors ? error.stack || '' : '';\n    const errorResponse = this.getResponse({\n      event,\n      statusCode: 500,\n      body,\n      headers: {},\n      isBase64Encoded: false,\n      log,\n    });\n\n    delegatedResolver.succeed(errorResponse);\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Get path from event with query strings\n   *\n   * @param event - The event sent by serverless\n   */\n  protected getPathFromEvent(event: ALBEvent): string {\n    const path = this.stripPathFn(event.path);\n\n    const queryParams = event.headers\n      ? event.queryStringParameters\n      : event.multiValueQueryStringParameters;\n\n    return getPathWithQueryStringParams(path, queryParams || {});\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/aws/api-gateway-v1.adapter.ts",
    "content": "//#region Imports\n\nimport type { APIGatewayProxyResult, Context } from 'aws-lambda';\nimport type { APIGatewayProxyEvent } from 'aws-lambda/trigger/api-gateway-proxy';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  GetResponseAdapterProps,\n  OnErrorProps,\n} from '../../contracts';\nimport { keysToLowercase } from '../../core';\nimport {\n  type StripBasePathFn,\n  buildStripBasePath,\n  getDefaultIfUndefined,\n  getEventBodyAsBuffer,\n  getMultiValueHeadersMap,\n  getPathWithQueryStringParams,\n} from '../../core';\n\n//#endregion\n\n/**\n * The options to customize the {@link ApiGatewayV1Adapter}\n *\n * @breadcrumb Adapters / AWS / ApiGatewayV1Adapter\n * @public\n */\nexport interface ApiGatewayV1Options {\n  /**\n   * Strip base path for custom domains\n   *\n   * @defaultValue ''\n   */\n  stripBasePath?: string;\n\n  /**\n   * Throw an exception when you send the `transfer-encoding=chunked`, currently, API Gateway doesn't support chunked transfer.\n   * If this is set to `false`, we will remove the `transfer-encoding` header from the response and buffer the response body\n   * while we remove the special characters inserted by the chunked encoding.\n   *\n   * @remarks To learn more https://github.com/H4ad/serverless-adapter/issues/165\n   * @defaultValue true\n   */\n  throwOnChunkedTransferEncoding?: boolean;\n\n  /**\n   * Emulates the behavior of Node.js `http` module by ensuring all request headers are lowercase.\n   *\n   * @defaultValue false\n   */\n  lowercaseRequestHeaders?: boolean;\n}\n\n/**\n * The adapter to handle requests from AWS Api Gateway V1\n *\n * As per {@link https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-known-issues.html | know issues}, we throw an exception when you send the `transfer-encoding=chunked`, currently, API Gateway doesn't support chunked transfer.\n *\n * @remarks This adapter is not fully compatible with \\@vendia/serverless-express, on \\@vendia they filter `transfer-encoding=chunked` but we throw an exception.\n *\n * @example\n * ```typescript\n * const stripBasePath = '/any/custom/base/path'; // default ''\n * const adapter = new ApiGatewayV1Adapter({ stripBasePath });\n * ```\n *\n * {@link https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html | Event Reference}\n *\n * @breadcrumb Adapters / AWS / ApiGatewayV1Adapter\n * @public\n */\nexport class ApiGatewayV1Adapter\n  implements\n    AdapterContract<APIGatewayProxyEvent, Context, APIGatewayProxyResult>\n{\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link ApiGatewayV1Adapter}\n   */\n  constructor(protected readonly options?: ApiGatewayV1Options) {\n    this.stripPathFn = buildStripBasePath(this.options?.stripBasePath);\n  }\n\n  //#endregion\n\n  //#region Protected Properties\n\n  /**\n   * Strip base path function\n   */\n  protected stripPathFn: StripBasePathFn;\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getAdapterName(): string {\n    return ApiGatewayV1Adapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public canHandle(event: unknown): event is APIGatewayProxyEvent {\n    const partialEventV1 = event as Partial<APIGatewayProxyEvent> & {\n      version?: '2.0';\n    };\n\n    return !!(\n      partialEventV1?.requestContext &&\n      partialEventV1.version !== '2.0' &&\n      partialEventV1.headers &&\n      partialEventV1.multiValueHeaders &&\n      ((partialEventV1.queryStringParameters === null &&\n        partialEventV1.multiValueQueryStringParameters === null) ||\n        (partialEventV1.queryStringParameters &&\n          partialEventV1.multiValueQueryStringParameters))\n    );\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getRequest(event: APIGatewayProxyEvent): AdapterRequest {\n    const method = event.httpMethod;\n    const headers = this.options?.lowercaseRequestHeaders\n      ? keysToLowercase(event.headers)\n      : { ...event.headers };\n\n    for (const multiValueHeaderKey of Object.keys(\n      event.multiValueHeaders || {},\n    )) {\n      const headerValue = event.multiValueHeaders[multiValueHeaderKey];\n\n      // event.headers by default only stick with first value if they see multiple headers\n      // the other values will only appear on multiValueHeaderKey, in this case\n      // we look for headers with more than 1 length which is the wrong values on event.headers\n      // https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html\n      if (!headerValue || headerValue?.length <= 1) continue;\n\n      headers[multiValueHeaderKey] = headerValue.join(',');\n    }\n\n    const path = this.getPathFromEvent(event);\n\n    let body: Buffer | undefined;\n\n    if (event.body) {\n      const [bufferBody, contentLength] = getEventBodyAsBuffer(\n        event.body,\n        event.isBase64Encoded,\n      );\n\n      body = bufferBody;\n      // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n      headers['content-length'] = contentLength + '';\n    }\n\n    const remoteAddress = event.requestContext.identity.sourceIp;\n\n    return {\n      method,\n      headers,\n      body,\n      remoteAddress,\n      path,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getResponse({\n    headers: responseHeaders,\n    body,\n    isBase64Encoded,\n    statusCode,\n    response,\n  }: GetResponseAdapterProps<APIGatewayProxyEvent>): APIGatewayProxyResult {\n    const multiValueHeaders = getMultiValueHeadersMap(responseHeaders);\n\n    const shouldThrowOnChunkedTransferEncoding = getDefaultIfUndefined(\n      this.options?.throwOnChunkedTransferEncoding,\n      true,\n    );\n    const transferEncodingHeader = multiValueHeaders['transfer-encoding'];\n    const hasTransferEncodingChunked = transferEncodingHeader?.some(value =>\n      value.includes('chunked'),\n    );\n\n    if (hasTransferEncodingChunked || response?.chunkedEncoding) {\n      if (shouldThrowOnChunkedTransferEncoding) {\n        throw new Error(\n          'chunked encoding in headers is not supported by API Gateway V1',\n        );\n      } else delete multiValueHeaders['transfer-encoding'];\n    }\n\n    return {\n      statusCode,\n      body,\n      multiValueHeaders,\n      isBase64Encoded,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public onErrorWhileForwarding({\n    error,\n    delegatedResolver,\n    respondWithErrors,\n    event,\n    log,\n  }: OnErrorProps<APIGatewayProxyEvent, APIGatewayProxyResult>): void {\n    const body = respondWithErrors ? error.stack : '';\n    const errorResponse = this.getResponse({\n      event,\n      statusCode: 500,\n      body: body || '',\n      headers: {},\n      isBase64Encoded: false,\n      log,\n    });\n\n    delegatedResolver.succeed(errorResponse);\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Get path from event with query strings\n   *\n   * @param event - The event sent by serverless\n   */\n  protected getPathFromEvent(event: APIGatewayProxyEvent): string {\n    const path = this.stripPathFn(event.path);\n    const queryParams = event.multiValueQueryStringParameters || {};\n\n    if (event.queryStringParameters) {\n      for (const queryStringKey of Object.keys(event.queryStringParameters)) {\n        const queryStringValue = event.queryStringParameters[queryStringKey];\n\n        if (queryStringValue === undefined) continue;\n\n        if (!Array.isArray(queryParams[queryStringKey]))\n          queryParams[queryStringKey] = [];\n\n        if (queryParams[queryStringKey]!.includes(queryStringValue)) continue;\n\n        queryParams[queryStringKey]!.push(queryStringValue);\n      }\n    }\n\n    return getPathWithQueryStringParams(path, queryParams);\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/aws/api-gateway-v2.adapter.ts",
    "content": "//#region Imports\n\nimport type { APIGatewayProxyEventV2, Context } from 'aws-lambda';\nimport type { APIGatewayProxyStructuredResultV2 } from 'aws-lambda/trigger/api-gateway-proxy';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  GetResponseAdapterProps,\n  OnErrorProps,\n} from '../../contracts';\nimport {\n  type StripBasePathFn,\n  buildStripBasePath,\n  getDefaultIfUndefined,\n  getEventBodyAsBuffer,\n  getFlattenedHeadersMapAndCookies,\n  getPathWithQueryStringParams,\n} from '../../core';\n\n//#endregion\n\n/**\n * The options to customize the {@link ApiGatewayV2Adapter}\n *\n * @breadcrumb Adapters / AWS / ApiGatewayV2Adapter\n * @public\n */\nexport interface ApiGatewayV2Options {\n  /**\n   * Strip base path for custom domains\n   *\n   * @defaultValue ''\n   */\n  stripBasePath?: string;\n\n  /**\n   * Throw an exception when you send the `transfer-encoding=chunked`, currently, API Gateway doesn't support chunked transfer.\n   * If this is set to `false`, we will remove the `transfer-encoding` header from the response and buffer the response body\n   * while we remove the special characters inserted by the chunked encoding.\n   *\n   * @remarks To learn more https://github.com/H4ad/serverless-adapter/issues/165\n   * @defaultValue true\n   */\n  throwOnChunkedTransferEncoding?: boolean;\n}\n\n/**\n * The adapter to handle requests from AWS Api Gateway V2\n *\n * As per {@link https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-known-issues.html | know issues}, we throw an exception when you send the `transfer-encoding=chunked`.\n * But, if you use this adapter to accept requests from Function URL, you can accept the `transfer-encoding=chunked` changing the method of invocation from `BUFFERED` to `RESPONSE_STREAM`.\n *\n * @example\n * ```typescript\n * const stripBasePath = '/any/custom/base/path'; // default ''\n * const adapter = new ApiGatewayV2Adapter({ stripBasePath });\n * ```\n *\n * {@link https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html | Event Reference}\n *\n * @breadcrumb Adapters / AWS / ApiGatewayV2Adapter\n * @public\n */\nexport class ApiGatewayV2Adapter\n  implements\n    AdapterContract<\n      APIGatewayProxyEventV2,\n      Context,\n      APIGatewayProxyStructuredResultV2\n    >\n{\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link ApiGatewayV2Adapter}\n   */\n  constructor(protected readonly options?: ApiGatewayV2Options) {\n    this.stripPathFn = buildStripBasePath(this.options?.stripBasePath);\n  }\n\n  //#endregion\n\n  //#region Protected Properties\n\n  /**\n   * Strip base path function\n   */\n  protected stripPathFn: StripBasePathFn;\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getAdapterName(): string {\n    return ApiGatewayV2Adapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public canHandle(event: unknown): event is APIGatewayProxyEventV2 {\n    const apiGatewayEvent = event as Partial<APIGatewayProxyEventV2> & {\n      version?: string;\n    };\n\n    return !!(\n      apiGatewayEvent?.requestContext && apiGatewayEvent.version === '2.0'\n    );\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getRequest(event: APIGatewayProxyEventV2): AdapterRequest {\n    const method = event.requestContext.http.method;\n    const path = this.getPathFromEvent(event);\n    // accords https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html\n    // all headers are lowercased and cannot be array\n    // so no need to format, just a shallow copy will work here\n    const headers = { ...event.headers };\n\n    if (event.cookies) headers.cookie = event.cookies.join('; ');\n\n    let body: Buffer | undefined;\n\n    if (event.body) {\n      const [bufferBody, contentLength] = getEventBodyAsBuffer(\n        event.body,\n        event.isBase64Encoded,\n      );\n\n      body = bufferBody;\n      // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n      headers['content-length'] = contentLength + '';\n    }\n\n    const remoteAddress = event.requestContext.http.sourceIp;\n\n    return {\n      method,\n      headers,\n      body,\n      remoteAddress,\n      path,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getResponse({\n    headers: responseHeaders,\n    body,\n    isBase64Encoded,\n    statusCode,\n    response,\n  }: GetResponseAdapterProps<APIGatewayProxyEventV2>): APIGatewayProxyStructuredResultV2 {\n    const { cookies, headers } =\n      getFlattenedHeadersMapAndCookies(responseHeaders);\n\n    const shouldThrowOnChunkedTransferEncoding = getDefaultIfUndefined(\n      this.options?.throwOnChunkedTransferEncoding,\n      true,\n    );\n\n    const transferEncodingHeader: string | undefined =\n      headers['transfer-encoding'];\n\n    const hasTransferEncodingChunked =\n      transferEncodingHeader && transferEncodingHeader.includes('chunked');\n\n    if (hasTransferEncodingChunked || response?.chunkedEncoding) {\n      if (shouldThrowOnChunkedTransferEncoding) {\n        throw new Error(\n          'chunked encoding in headers is not supported by API Gateway V2',\n        );\n      } else delete headers['transfer-encoding'];\n    }\n\n    return {\n      statusCode,\n      body,\n      headers,\n      isBase64Encoded,\n      cookies,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public onErrorWhileForwarding({\n    error,\n    delegatedResolver,\n    respondWithErrors,\n    event,\n    log,\n  }: OnErrorProps<\n    APIGatewayProxyEventV2,\n    APIGatewayProxyStructuredResultV2\n  >): void {\n    const body = respondWithErrors ? error.stack : '';\n    const errorResponse = this.getResponse({\n      event,\n      statusCode: 500,\n      body: body || '',\n      headers: {},\n      isBase64Encoded: false,\n      log,\n    });\n\n    delegatedResolver.succeed(errorResponse);\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Get path from event with query strings\n   *\n   * @param event - The event sent by serverless\n   */\n  protected getPathFromEvent(event: APIGatewayProxyEventV2): string {\n    const path = this.stripPathFn(event.rawPath);\n    const queryParams = event.rawQueryString;\n\n    return getPathWithQueryStringParams(path, queryParams || {});\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/aws/base/aws-simple-adapter.ts",
    "content": "//#region Imports\n\nimport type { Context, SQSBatchItemFailure } from 'aws-lambda';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  GetResponseAdapterProps,\n  OnErrorProps,\n} from '../../../contracts';\nimport {\n  EmptyResponse,\n  type IEmptyResponse,\n  getEventBodyAsBuffer,\n} from '../../../core';\n\n//#endregion\n\n/**\n * The options to customize the {@link AwsSimpleAdapter}\n *\n * @breadcrumb Adapters / AWS / AWS Simple Adapter\n * @public\n */\nexport interface AWSSimpleAdapterOptions {\n  /**\n   * The path that will be used to create a request to be forwarded to the framework.\n   */\n  forwardPath: string;\n\n  /**\n   * The http method that will be used to create a request to be forwarded to the framework.\n   */\n  forwardMethod: string;\n\n  /**\n   * The AWS Service host that will be injected inside headers to developer being able to validate if request originate from the library.\n   */\n  host: string;\n\n  /**\n   * Tells if this adapter should support batch item failures.\n   */\n  batch?: true | false;\n}\n\n/**\n * The batch item failure response expected from the API server\n *\n * @breadcrumb Adapters / AWS / AWS Simple Adapter\n * @public\n */\nexport type BatchItemFailureResponse = SQSBatchItemFailure;\n\n/**\n * The possible options of response for {@link AwsSimpleAdapter}\n *\n * @breadcrumb Adapters / AWS / AWS Simple Adapter\n * @public\n */\nexport type AWSSimpleAdapterResponseType =\n  | BatchItemFailureResponse\n  | IEmptyResponse;\n\n/**\n * The abstract adapter to use to implement other simple AWS adapters\n *\n * @breadcrumb Adapters / AWS / AWS Simple Adapter\n * @public\n */\nexport abstract class AwsSimpleAdapter<TEvent>\n  implements AdapterContract<TEvent, Context, AWSSimpleAdapterResponseType>\n{\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link AwsSimpleAdapter}\n   */\n  constructor(protected readonly options: AWSSimpleAdapterOptions) {}\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getAdapterName(): string {\n    throw new Error('not implemented.');\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public canHandle(_: unknown): _ is TEvent {\n    throw new Error('not implemented.');\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getRequest(event: TEvent): AdapterRequest {\n    const path = this.options.forwardPath;\n    const method = this.options.forwardMethod;\n\n    const [body, contentLength] = getEventBodyAsBuffer(\n      JSON.stringify(event),\n      false,\n    );\n\n    const headers = {\n      host: this.options.host,\n      'content-type': 'application/json',\n      'content-length': String(contentLength),\n    };\n\n    return {\n      method,\n      headers,\n      body,\n      path,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getResponse({\n    body,\n    headers,\n    isBase64Encoded,\n    event,\n    statusCode,\n  }: GetResponseAdapterProps<TEvent>): AWSSimpleAdapterResponseType {\n    if (this.hasInvalidStatusCode(statusCode)) {\n      throw new Error(\n        JSON.stringify({ body, headers, isBase64Encoded, event, statusCode }),\n      );\n    }\n\n    if (!this.options.batch) return EmptyResponse;\n\n    if (isBase64Encoded) {\n      throw new Error(\n        'SERVERLESS_ADAPTER: The response could not be base64 encoded when you set batch: true, the response should be a JSON.',\n      );\n    }\n\n    if (!body) return EmptyResponse;\n\n    return JSON.parse(body);\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public onErrorWhileForwarding({\n    error,\n    delegatedResolver,\n  }: OnErrorProps<TEvent, AWSSimpleAdapterResponseType>): void {\n    delegatedResolver.fail(error);\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Check if the status code is invalid\n   *\n   * @param statusCode - The status code\n   */\n  protected hasInvalidStatusCode(statusCode: number): boolean {\n    return statusCode < 200 || statusCode >= 400;\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/aws/base/index.ts",
    "content": "export * from './aws-simple-adapter';\n"
  },
  {
    "path": "src/adapters/aws/dynamodb.adapter.ts",
    "content": "//#region Imports\n\nimport type { DynamoDBStreamEvent } from 'aws-lambda';\nimport { getDefaultIfUndefined } from '../../core';\nimport { type AWSSimpleAdapterOptions, AwsSimpleAdapter } from './base/index';\n\n//#endregion\n\n/**\n * The options to customize the {@link DynamoDBAdapter}\n *\n * @breadcrumb Adapters / AWS / DynamoDBAdapter\n * @public\n */\nexport interface DynamoDBAdapterOptions\n  extends Pick<AWSSimpleAdapterOptions, 'batch'> {\n  /**\n   * The path that will be used to create a request to be forwarded to the framework.\n   *\n   * @defaultValue /dynamo\n   */\n  dynamoDBForwardPath?: string;\n\n  /**\n   * The http method that will be used to create a request to be forwarded to the framework.\n   *\n   * @defaultValue POST\n   */\n  dynamoDBForwardMethod?: string;\n}\n\n/**\n * The adapter to handle requests from AWS DynamoDB.\n *\n * The option of `responseWithErrors` is ignored by this adapter and we always call `resolver.fail` with the error.\n *\n * {@link https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html | Event Reference}\n *\n * @example\n * ```typescript\n * const dynamoDBForwardPath = '/your/route/dynamo'; // default /dynamo\n * const dynamoDBForwardMethod = 'POST'; // default POST\n * const adapter = new DynamoDBAdapter({ dynamoDBForwardPath, dynamoDBForwardMethod });\n * ```\n *\n * @breadcrumb Adapters / AWS / DynamoDBAdapter\n * @public\n */\nexport class DynamoDBAdapter extends AwsSimpleAdapter<DynamoDBStreamEvent> {\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link DynamoDBAdapter}\n   */\n  constructor(options?: DynamoDBAdapterOptions) {\n    super({\n      forwardPath: getDefaultIfUndefined(\n        options?.dynamoDBForwardPath,\n        '/dynamo',\n      ),\n      forwardMethod: getDefaultIfUndefined(\n        options?.dynamoDBForwardMethod,\n        'POST',\n      ),\n      batch: options?.batch,\n      host: 'dynamodb.amazonaws.com',\n    });\n  }\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public override getAdapterName(): string {\n    return DynamoDBAdapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public override canHandle(event: unknown): event is DynamoDBStreamEvent {\n    const dynamoDBevent = event as Partial<DynamoDBStreamEvent>;\n\n    if (!Array.isArray(dynamoDBevent?.Records)) return false;\n\n    const eventSource = dynamoDBevent.Records[0]?.eventSource;\n\n    return eventSource === 'aws:dynamodb';\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/aws/event-bridge.adapter.ts",
    "content": "//#region Imports\n\nimport type { EventBridgeEvent } from 'aws-lambda';\nimport { getDefaultIfUndefined } from '../../core';\nimport { AwsSimpleAdapter } from './base';\n\n//#endregion\n\n/**\n * The options to customize the {@link EventBridgeAdapter}\n *\n * @breadcrumb Adapters / AWS / EventBridgeAdapter\n * @public\n */\nexport interface EventBridgeOptions {\n  /**\n   * The path that will be used to create a request to be forwarded to the framework.\n   *\n   * @defaultValue /eventbridge\n   */\n  eventBridgeForwardPath?: string;\n\n  /**\n   * The http method that will be used to create a request to be forwarded to the framework.\n   *\n   * @defaultValue POST\n   */\n  eventBridgeForwardMethod?: string;\n}\n\n/**\n * Just a type alias to ignore generic types in the event\n *\n * @breadcrumb Adapters / AWS / EventBridgeAdapter\n * @public\n */\nexport type EventBridgeEventAll = EventBridgeEvent<any, any>;\n\n/**\n * The adapter to handle requests from AWS EventBridge (Cloudwatch Events).\n *\n * The option of `responseWithErrors` is ignored by this adapter and we always call `resolver.fail` with the error.\n *\n * {@link https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents.html | Event Reference}\n *\n * @example\n * ```typescript\n * const eventBridgeForwardPath = '/your/route/eventbridge'; // default /eventbridge\n * const eventBridgeForwardMethod = 'POST'; // default POST\n * const adapter = new EventBridgeAdapter({ eventBridgeForwardPath, eventBridgeForwardMethod });\n * ```\n *\n * @breadcrumb Adapters / AWS / EventBridgeAdapter\n * @public\n */\nexport class EventBridgeAdapter extends AwsSimpleAdapter<EventBridgeEventAll> {\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link EventBridgeAdapter}\n   */\n  constructor(options?: EventBridgeOptions) {\n    super({\n      forwardPath: getDefaultIfUndefined(\n        options?.eventBridgeForwardPath,\n        '/eventbridge',\n      ),\n      forwardMethod: getDefaultIfUndefined(\n        options?.eventBridgeForwardMethod,\n        'POST',\n      ),\n      batch: false,\n      host: 'events.amazonaws.com',\n    });\n  }\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public override getAdapterName(): string {\n    return EventBridgeAdapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public override canHandle(event: unknown): event is EventBridgeEventAll {\n    const eventBridgeEvent = event as Partial<EventBridgeEventAll>;\n\n    // thanks to @cnuss in https://github.com/vendia/serverless-express/blob/b5da6070b8dd2fb674c1f7035dd7edfef1dc83a2/src/event-sources/utils.js#L87\n    return !!(\n      eventBridgeEvent &&\n      eventBridgeEvent.version &&\n      eventBridgeEvent.version === '0' &&\n      eventBridgeEvent.id &&\n      eventBridgeEvent['detail-type'] &&\n      eventBridgeEvent.source &&\n      eventBridgeEvent.account &&\n      eventBridgeEvent.time &&\n      eventBridgeEvent.region &&\n      eventBridgeEvent.resources &&\n      Array.isArray(eventBridgeEvent.resources) &&\n      eventBridgeEvent.detail &&\n      typeof eventBridgeEvent.detail === 'object' &&\n      !Array.isArray(eventBridgeEvent.detail)\n    );\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/aws/index.ts",
    "content": "export * from './alb.adapter';\nexport * from './api-gateway-v1.adapter';\nexport * from './api-gateway-v2.adapter';\nexport * from './dynamodb.adapter';\nexport * from './event-bridge.adapter';\nexport * from './lambda-edge.adapter';\nexport * from './s3.adapter';\nexport * from './sns.adapter';\nexport * from './sqs.adapter';\nexport * from './base';\nexport * from './request-lambda-edge.adapter';\n"
  },
  {
    "path": "src/adapters/aws/lambda-edge.adapter.ts",
    "content": "//#region Imports\n\nimport type { CloudFrontRequest, Context } from 'aws-lambda';\nimport type {\n  CloudFrontEvent,\n  CloudFrontHeaders,\n  CloudFrontResultResponse,\n} from 'aws-lambda/common/cloudfront';\nimport type {\n  CloudFrontRequestEvent,\n  CloudFrontRequestResult,\n} from 'aws-lambda/trigger/cloudfront-request';\nimport type {\n  BothValueHeaders,\n  Concrete,\n  SingleValueHeaders,\n} from '../../@types';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  GetResponseAdapterProps,\n  OnErrorProps,\n} from '../../contracts';\nimport {\n  getDefaultIfUndefined,\n  getEventBodyAsBuffer,\n  getPathWithQueryStringParams,\n} from '../../core';\n\n//#endregion\n\n/**\n * The type alias to indicate where we get the default value of query string to create the request.\n *\n * @breadcrumb Adapters / AWS / LambdaEdgeAdapter\n * @public\n */\nexport type DefaultQueryString =\n  CloudFrontRequestEvent['Records'][number]['cf']['request']['querystring'];\n\n/**\n * The type alias to indicate where we get the default value of path to create the request.\n *\n * @breadcrumb Adapters / AWS / LambdaEdgeAdapter\n * @public\n */\nexport type DefaultForwardPath =\n  CloudFrontRequestEvent['Records'][number]['cf']['request']['uri'];\n\n/**\n * Represents the body of the new version of Lambda\\@edge, which uses the `body` property inside `request` as the body (library) of the request.\n *\n * @breadcrumb Adapters / AWS / LambdaEdgeAdapter\n * @public\n */\nexport type NewLambdaEdgeBody =\n  CloudFrontRequestEvent['Records'][number]['cf']['request']['body'];\n\n/**\n * Represents the body of the old version of Lambda\\@edge supported by \\@vendia/serverless-express which returns the `data` property within `body` for the body (library) of the request.\n *\n * @breadcrumb Adapters / AWS / LambdaEdgeAdapter\n * @public\n */\nexport type OldLambdaEdgeBody = Concrete<\n  CloudFrontRequestEvent['Records'][number]['cf']['request']\n>['body']['data'];\n\n/**\n * The list was created based on {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/edge-functions-restrictions.html | these docs} in the \"Disallowed Headers\" section.\n *\n * @breadcrumb Adapters / AWS / LambdaEdgeAdapter / Constants\n * @public\n */\nexport const DEFAULT_LAMBDA_EDGE_DISALLOWED_HEADERS: (string | RegExp)[] = [\n  'Connection',\n  'Expect',\n  'Keep-Alive',\n  'Proxy-Authenticate',\n  'Proxy-Authorization',\n  'Proxy-Connection',\n  'Trailer',\n  'Upgrade',\n  'X-Accel-Buffering',\n  'X-Accel-Charset',\n  'X-Accel-Limit-Rate',\n  'X-Accel-Redirect',\n  /(X-Amz-Cf-)(.*)/gim,\n  'X-Cache',\n  /(X-Edge-)(.*)/gim,\n  'X-Forwarded-Proto',\n  'X-Real-IP',\n];\n\n/**\n * The default max response size in bytes of viewer request and viewer response.\n *\n * @defaultValue 1024 * 40 = 40960 = 40KB\n *\n * {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html | Reference}\n *\n * @breadcrumb Adapters / AWS / LambdaEdgeAdapter / Constants\n * @public\n */\nexport const DEFAULT_VIEWER_MAX_RESPONSE_SIZE_IN_BYTES = 1024 * 40;\n\n/**\n * The default max response size in bytes of origin request and origin response.\n *\n * @defaultValue 1024 * 1024 = 1048576 = 1MB\n *\n * {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html | Reference}\n *\n * @breadcrumb Adapters / AWS / LambdaEdgeAdapter / Constants\n * @public\n */\nexport const DEFAULT_ORIGIN_MAX_RESPONSE_SIZE_IN_BYTES = 1024 * 1024;\n\n/**\n * The options to customize the {@link LambdaEdgeAdapter}.\n *\n * @breadcrumb Adapters / AWS / LambdaEdgeAdapter\n * @public\n */\nexport interface LambdaEdgeAdapterOptions {\n  /**\n   * The max response size in bytes of viewer request and viewer response.\n   *\n   * {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html | Reference}\n   *\n   * @defaultValue {@link DEFAULT_VIEWER_MAX_RESPONSE_SIZE_IN_BYTES}\n   */\n  viewerMaxResponseSizeInBytes?: number;\n\n  /**\n   * The max response size in bytes of origin request and origin response.\n   *\n   * {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html | Reference}\n   *\n   * @defaultValue {@link DEFAULT_ORIGIN_MAX_RESPONSE_SIZE_IN_BYTES}\n   */\n  originMaxResponseSizeInBytes?: number;\n\n  /**\n   * The function called when the response size exceed the max limits of the Lambda\\@edge\n   *\n   * @param response - The response from framework that exceed the limit of Lambda\\@edge\n   * @defaultValue undefined\n   */\n  onResponseSizeExceedLimit?: (\n    response: CloudFrontRequestResult,\n  ) => CloudFrontRequestResult;\n\n  /**\n   * Return the path to be used to create a request to the framework\n   *\n   * @remarks You MUST append the query params from {@link DefaultQueryString}, you can use the helper {@link getPathWithQueryStringParams}.\n   *\n   * @param event - The event sent by the serverless\n   * @defaultValue The value from {@link DefaultForwardPath}\n   */\n  getPathFromEvent?: (\n    event: CloudFrontRequestEvent['Records'][number],\n  ) => string;\n\n  /**\n   * The headers that will be stripped from the headers object because Lambda\\@edge will fail if these headers are passed in the response.\n   *\n   * @remarks All headers will be compared with other headers using toLowerCase, but for the RegExp, if you modify this list, you must put the flag `/gmi` at the end of the RegExp (ex: `/(X-Amz-Cf-)(.*)/gim`)\n   *\n   * @defaultValue To get the full list, see {@link DEFAULT_LAMBDA_EDGE_DISALLOWED_HEADERS}.\n   */\n  disallowedHeaders?: (string | RegExp)[];\n\n  /**\n   * If you want to change how we check against the header if it should be stripped, you can pass a function to this property.\n   *\n   * @param header - The header of the response\n   * @defaultValue The default method is implemented to test the header against the list {@link LambdaEdgeAdapterOptions.disallowedHeaders}.\n   */\n  shouldStripHeader?: (header: string) => boolean;\n\n  /**\n   * By default, the {@link aws-lambda#CloudFrontRequestResult} has the `headers` property, but we also have the headers sent by the framework too.\n   * So this setting tells us how to handle this case, if you pass `true` to this property, we will use the framework headers.\n   * Otherwise, we will forward the body back to cloudfront without modifying or trying to set the `headers` property inside {@link aws-lambda#CloudFrontRequestResult}.\n   *\n   * @defaultValue false\n   */\n  shouldUseHeadersFromFramework?: boolean;\n}\n\n/**\n * The adapter to handle requests from AWS Lambda\\@Edge.\n *\n * This adapter is not fully compatible with Lambda\\@edge supported by \\@vendia/serverless-express, the request body was modified to return {@link NewLambdaEdgeBody} instead {@link OldLambdaEdgeBody}.\n * Also, the response has been modified to return entire body sent by the framework, in this form you MUST return the body from the framework in the format of {@link aws-lambda#CloudFrontRequestResult}.\n * And when we get an error during the forwarding to the framework, we call `resolver.fail` instead of trying to return status 500 like the old implementation was.\n *\n * {@link https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html | Lambda edge docs}\n * {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html | Event Reference}\n *\n * @example\n * ```typescript\n * const getPathFromEvent = () => '/lambda/edge'; // will forward all requests to the same endpoint\n * const adapter = new LambdaEdgeAdapter({ getPathFromEvent });\n * ```\n *\n * @breadcrumb Adapters / AWS / LambdaEdgeAdapter\n * @public\n */\nexport class LambdaEdgeAdapter\n  implements\n    AdapterContract<CloudFrontRequestEvent, Context, CloudFrontRequestResult>\n{\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link LambdaEdgeAdapter}\n   */\n  constructor(protected readonly options?: LambdaEdgeAdapterOptions) {\n    const disallowedHeaders = getDefaultIfUndefined(\n      this.options?.disallowedHeaders,\n      DEFAULT_LAMBDA_EDGE_DISALLOWED_HEADERS,\n    );\n\n    this.cachedDisallowedHeaders = disallowedHeaders.map(disallowedHeader => {\n      if (disallowedHeader instanceof RegExp) return disallowedHeader;\n\n      return new RegExp(`(${disallowedHeader})`, 'gim');\n    });\n  }\n\n  //#endregion\n\n  //#region Protected Properties\n\n  /**\n   * This property is used to cache the disallowed headers in `RegExp` version, even if you provide a string in `disallowedHeader`, we will cache it in an instance of `RegExp`.\n   */\n  protected readonly cachedDisallowedHeaders: RegExp[];\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getAdapterName(): string {\n    return LambdaEdgeAdapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public canHandle(event: unknown): event is CloudFrontRequestEvent {\n    const lambdaEdgeEvent = event as Partial<CloudFrontRequestEvent>;\n\n    if (!Array.isArray(lambdaEdgeEvent?.Records)) return false;\n\n    const eventType = lambdaEdgeEvent.Records[0]?.cf?.config?.eventType;\n    const validEventTypes: CloudFrontEvent['config']['eventType'][] = [\n      'origin-response',\n      'origin-request',\n      'viewer-response',\n      'viewer-request',\n    ];\n\n    return validEventTypes.includes(eventType);\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getRequest(event: CloudFrontRequestEvent): AdapterRequest {\n    const request = event.Records[0];\n    const cloudFrontRequest = request.cf.request;\n\n    const method = cloudFrontRequest.method;\n\n    const pathFromOptions = this.options?.getPathFromEvent\n      ? this.options.getPathFromEvent(request)\n      : undefined;\n    const defaultPath = getPathWithQueryStringParams(\n      cloudFrontRequest.uri,\n      cloudFrontRequest.querystring,\n    );\n    const path = getDefaultIfUndefined(pathFromOptions, defaultPath);\n\n    const remoteAddress = cloudFrontRequest.clientIp;\n\n    const headers =\n      this.getFlattenedHeadersFromCloudfrontRequest(cloudFrontRequest);\n\n    let body: Buffer | undefined;\n\n    if (cloudFrontRequest.body) {\n      const [buffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(cloudFrontRequest.body),\n        false,\n      );\n\n      body = buffer;\n      headers['content-length'] = contentLength.toString();\n    }\n\n    const { host } = headers;\n\n    return {\n      method,\n      path,\n      headers,\n      body,\n      remoteAddress,\n      host,\n      hostname: host,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getResponse(\n    props: GetResponseAdapterProps<CloudFrontRequestEvent>,\n  ): CloudFrontRequestResult {\n    const response = this.getResponseToLambdaEdge(props);\n    const responseToServiceBytes = new TextEncoder().encode(\n      JSON.stringify(response),\n    ).length;\n\n    const isOriginRequestOrResponse = this.isEventTypeOrigin(\n      props.event.Records[0].cf.config,\n    );\n    const maxSizeInBytes = isOriginRequestOrResponse\n      ? getDefaultIfUndefined(\n          this.options?.originMaxResponseSizeInBytes,\n          DEFAULT_ORIGIN_MAX_RESPONSE_SIZE_IN_BYTES,\n        )\n      : getDefaultIfUndefined(\n          this.options?.viewerMaxResponseSizeInBytes,\n          DEFAULT_VIEWER_MAX_RESPONSE_SIZE_IN_BYTES,\n        );\n\n    if (responseToServiceBytes <= maxSizeInBytes) return response;\n\n    if (this.options?.onResponseSizeExceedLimit)\n      this.options.onResponseSizeExceedLimit(response);\n    else {\n      props.log.error(\n        `SERVERLESS_ADAPTER:LAMBDA_EDGE_ADAPTER: Max response size exceeded: ${responseToServiceBytes} of the max of ${maxSizeInBytes}.`,\n      );\n    }\n\n    return response;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public onErrorWhileForwarding({\n    error,\n    delegatedResolver,\n  }: OnErrorProps<CloudFrontRequestEvent, CloudFrontRequestResult>): void {\n    delegatedResolver.fail(error);\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Returns the headers with the flattened (non-list) values of the cloudfront request headers\n   *\n   * @param cloudFrontRequest - The cloudfront request\n   */\n  protected getFlattenedHeadersFromCloudfrontRequest(\n    cloudFrontRequest: CloudFrontRequest,\n  ): SingleValueHeaders {\n    return Object.keys(cloudFrontRequest.headers).reduce((acc, headerKey) => {\n      const headerValue = cloudFrontRequest.headers[headerKey];\n\n      acc[headerKey] = headerValue.map(header => header.value).join(',');\n\n      return acc;\n    }, {} as SingleValueHeaders);\n  }\n\n  /**\n   * Returns the framework response in the format required by the Lambda\\@edge.\n   *\n   * @param body - The body of the response\n   * @param frameworkHeaders - The headers from the framework\n   */\n  protected getResponseToLambdaEdge({\n    body,\n    headers: frameworkHeaders,\n  }: GetResponseAdapterProps<CloudFrontRequestEvent>): CloudFrontRequestResult {\n    const shouldUseHeadersFromFramework = getDefaultIfUndefined(\n      this.options?.shouldUseHeadersFromFramework,\n      false,\n    );\n\n    const parsedBody: CloudFrontResultResponse | CloudFrontRequest =\n      JSON.parse(body);\n\n    if (parsedBody.headers) {\n      parsedBody.headers = Object.keys(parsedBody.headers).reduce(\n        (acc, header) => {\n          if (this.shouldStripHeader(header)) return acc;\n\n          acc[header] = parsedBody.headers![header];\n\n          return acc;\n        },\n        {} as CloudFrontHeaders,\n      );\n    }\n\n    if (!shouldUseHeadersFromFramework) return parsedBody;\n\n    parsedBody.headers = this.getHeadersForCloudfrontResponse(frameworkHeaders);\n\n    return parsedBody;\n  }\n\n  /**\n   * Returns headers in Cloudfront Response format.\n   *\n   * @param originalHeaders - The original version of the request sent by the framework\n   */\n  protected getHeadersForCloudfrontResponse(\n    originalHeaders: BothValueHeaders,\n  ): CloudFrontHeaders {\n    return Object.keys(originalHeaders).reduce((acc, headerKey) => {\n      if (this.shouldStripHeader(headerKey)) return acc;\n\n      if (!acc[headerKey]) acc[headerKey] = [];\n\n      const headerValue = originalHeaders[headerKey];\n\n      if (!Array.isArray(headerValue)) {\n        acc[headerKey].push({\n          key: headerKey,\n          value: headerValue || '',\n        });\n\n        return acc;\n      }\n\n      const headersArray = headerValue.map(value => ({\n        key: headerKey,\n        value: value,\n      }));\n\n      acc[headerKey].push(...headersArray);\n\n      return acc;\n    }, {} as CloudFrontHeaders);\n  }\n\n  /**\n   * Returns the information if we should remove the response header\n   *\n   * @param headerKey - The header that will be tested\n   */\n  protected shouldStripHeader(headerKey: string): boolean {\n    if (this.options?.shouldStripHeader)\n      return this.options.shouldStripHeader(headerKey);\n\n    const headerKeyLowerCase = headerKey.toLowerCase();\n\n    for (const stripHeaderIf of this.cachedDisallowedHeaders) {\n      if (!stripHeaderIf.test(headerKeyLowerCase)) continue;\n\n      return true;\n    }\n\n    return false;\n  }\n\n  /**\n   * Determines whether the event is from origin or is from viewer.\n   *\n   * @param content - The event sent by AWS or the response sent by the framework\n   */\n  protected isEventTypeOrigin(content: CloudFrontEvent['config']): boolean {\n    return content.eventType.includes('origin');\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/aws/request-lambda-edge.adapter.ts",
    "content": "//#region Imports\n\nimport type { CloudFrontRequest, Context } from 'aws-lambda';\nimport type {\n  CloudFrontHeaders,\n  CloudFrontResultResponse,\n} from 'aws-lambda/common/cloudfront';\nimport type {\n  CloudFrontRequestEvent,\n  CloudFrontRequestResult,\n} from 'aws-lambda/trigger/cloudfront-request';\nimport type { BothValueHeaders, SingleValueHeaders } from '../../@types';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  GetResponseAdapterProps,\n  OnErrorProps,\n} from '../../contracts';\nimport {\n  type StripBasePathFn,\n  buildStripBasePath,\n  getDefaultIfUndefined,\n  getEventBodyAsBuffer,\n  getPathWithQueryStringParams,\n} from '../../core';\nimport {\n  DEFAULT_LAMBDA_EDGE_DISALLOWED_HEADERS,\n  DEFAULT_ORIGIN_MAX_RESPONSE_SIZE_IN_BYTES,\n  DEFAULT_VIEWER_MAX_RESPONSE_SIZE_IN_BYTES,\n} from './lambda-edge.adapter';\n\n//#endregion\n\n//#endregion\n\n/**\n * The options to customize the {@link RequestLambdaEdgeAdapter}.\n *\n * @breadcrumb Adapters / AWS / RequestLambdaEdgeAdapter\n * @public\n */\nexport interface RequestLambdaEdgeAdapterOptions {\n  /**\n   * Strip base path for custom paths, like `/api`.\n   *\n   * @defaultValue ''\n   */\n  stripBasePath?: string;\n\n  /**\n   * The max response size in bytes of viewer request and viewer response.\n   *\n   * {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html | Reference}\n   *\n   * @defaultValue {@link DEFAULT_VIEWER_MAX_RESPONSE_SIZE_IN_BYTES}\n   */\n  viewerMaxResponseSizeInBytes?: number;\n\n  /**\n   * The max response size in bytes of origin request and origin response.\n   *\n   * {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html | Reference}\n   *\n   * @defaultValue {@link DEFAULT_ORIGIN_MAX_RESPONSE_SIZE_IN_BYTES}\n   */\n  originMaxResponseSizeInBytes?: number;\n\n  /**\n   * The function called when the response size exceed the max limits of the Lambda\\@edge\n   *\n   * @param response - The response from framework that exceed the limit of Lambda\\@edge\n   * @defaultValue undefined\n   */\n  onResponseSizeExceedLimit?: (\n    response: CloudFrontRequestResult,\n  ) => CloudFrontRequestResult;\n\n  /**\n   * The headers that will be stripped from the headers object because Lambda\\@edge will fail if these headers are passed in the response.\n   *\n   * @remarks All headers will be compared with other headers using toLowerCase, but for the RegExp, if you modify this list, you must put the flag `/gmi` at the end of the RegExp (ex: `/(X-Amz-Cf-)(.*)/gim`)\n   *\n   * @defaultValue To get the full list, see {@link DEFAULT_LAMBDA_EDGE_DISALLOWED_HEADERS}.\n   */\n  disallowedHeaders?: (string | RegExp)[];\n\n  /**\n   * If you want to change how we check against the header if it should be stripped, you can pass a function to this property.\n   *\n   * @param header - The header of the response\n   * @defaultValue The default method is implemented to test the header against the list {@link RequestLambdaEdgeAdapterOptions.disallowedHeaders}.\n   */\n  shouldStripHeader?: (header: string) => boolean;\n}\n\n/**\n * The adapter to handle requests from AWS Lambda\\@Edge of the type Viewer Request.\n *\n * The idea of this Adapter is to you be able to expose your framework to the Edge, like when you build for Cloudfront.\n *\n * {@link https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html | Lambda edge docs}\n * {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html | Event Reference}\n *\n * @example\n * ```typescript\n * const stripBasePath = '/api'; // in case you have configure the cloudfront to forward the path /api to your lambda\n * const adapter = new RequestLambdaEdgeAdapter({ stripBasePath });\n * ```\n *\n * @breadcrumb Adapters / AWS / RequestLambdaEdgeAdapter\n * @public\n */\nexport class RequestLambdaEdgeAdapter\n  implements\n    AdapterContract<CloudFrontRequestEvent, Context, CloudFrontResultResponse>\n{\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link RequestLambdaEdgeAdapter}\n   */\n  constructor(protected readonly options?: RequestLambdaEdgeAdapterOptions) {\n    this.stripPathFn = buildStripBasePath(this.options?.stripBasePath);\n\n    const disallowedHeaders = getDefaultIfUndefined(\n      this.options?.disallowedHeaders,\n      DEFAULT_LAMBDA_EDGE_DISALLOWED_HEADERS,\n    );\n\n    this.cachedDisallowedHeaders = disallowedHeaders.map(disallowedHeader => {\n      if (disallowedHeader instanceof RegExp) return disallowedHeader;\n\n      return new RegExp(`(${disallowedHeader})`, 'gim');\n    });\n  }\n\n  //#endregion\n\n  //#region Protected Properties\n\n  /**\n   * Strip base path function\n   */\n  protected readonly stripPathFn: StripBasePathFn;\n\n  /**\n   * This property is used to cache the disallowed headers in `RegExp` version, even if you provide a string in `disallowedHeader`, we will cache it in an instance of `RegExp`.\n   */\n  protected readonly cachedDisallowedHeaders: RegExp[];\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getAdapterName(): string {\n    return RequestLambdaEdgeAdapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public canHandle(event: unknown): event is CloudFrontRequestEvent {\n    const lambdaEdgeEvent = event as Partial<CloudFrontRequestEvent>;\n\n    if (!Array.isArray(lambdaEdgeEvent?.Records)) return false;\n\n    const eventType = lambdaEdgeEvent.Records[0]?.cf?.config?.eventType;\n\n    return eventType === 'viewer-request' || eventType === 'origin-request';\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getRequest(event: CloudFrontRequestEvent): AdapterRequest {\n    const request = event.Records[0];\n    const cloudFrontRequest = request.cf.request;\n\n    const method = cloudFrontRequest.method;\n\n    const path = this.stripPathFn(\n      getPathWithQueryStringParams(\n        cloudFrontRequest.uri,\n        cloudFrontRequest.querystring,\n      ),\n    );\n    const remoteAddress = cloudFrontRequest.clientIp;\n\n    const headers =\n      this.getFlattenedHeadersFromCloudfrontRequest(cloudFrontRequest);\n\n    let body: Buffer | undefined;\n\n    if (cloudFrontRequest.body) {\n      const [buffer, contentLength] = getEventBodyAsBuffer(\n        cloudFrontRequest.body.data,\n        cloudFrontRequest.body.encoding === 'base64',\n      );\n\n      body = buffer;\n      headers['content-length'] = contentLength.toString();\n    }\n\n    const { host } = headers;\n\n    return {\n      method,\n      path,\n      headers,\n      body,\n      remoteAddress,\n      host,\n      hostname: host,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getResponse({\n    body,\n    headers: frameworkHeaders,\n    isBase64Encoded,\n    statusCode,\n    log,\n    event,\n  }: GetResponseAdapterProps<CloudFrontRequestEvent>): CloudFrontResultResponse {\n    const headers = this.getHeadersForCloudfrontResponse(frameworkHeaders);\n\n    const maxSizeInBytes =\n      event.Records[0].cf.config.eventType === 'origin-request'\n        ? getDefaultIfUndefined(\n            this.options?.originMaxResponseSizeInBytes,\n            DEFAULT_ORIGIN_MAX_RESPONSE_SIZE_IN_BYTES,\n          )\n        : getDefaultIfUndefined(\n            this.options?.viewerMaxResponseSizeInBytes,\n            DEFAULT_VIEWER_MAX_RESPONSE_SIZE_IN_BYTES,\n          );\n\n    const response: CloudFrontResultResponse = {\n      body,\n      status: statusCode.toString(),\n      bodyEncoding: isBase64Encoded ? 'base64' : 'text',\n      headers,\n    };\n\n    // probably is not correctly accurate, but it's a good approximation\n    const bodyLength = body.length;\n\n    if (bodyLength <= maxSizeInBytes) return response;\n\n    if (this.options?.onResponseSizeExceedLimit)\n      this.options.onResponseSizeExceedLimit(response);\n    else {\n      log.error(\n        `SERVERLESS_ADAPTER:LAMBDA_EDGE_ADAPTER: Max response size exceeded: ${bodyLength} of the max of ${maxSizeInBytes}.`,\n      );\n    }\n\n    return response;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public onErrorWhileForwarding({\n    error,\n    delegatedResolver,\n    respondWithErrors,\n    log,\n    event,\n  }: OnErrorProps<CloudFrontRequestEvent, CloudFrontRequestResult>): void {\n    const body = respondWithErrors ? error.stack : '';\n    const errorResponse = this.getResponse({\n      event,\n      statusCode: 500,\n      body: body || '',\n      headers: {},\n      isBase64Encoded: false,\n      log,\n    });\n\n    delegatedResolver.succeed(errorResponse);\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Returns the headers with the flattened (non-list) values of the cloudfront request headers\n   *\n   * @param cloudFrontRequest - The cloudfront request\n   */\n  protected getFlattenedHeadersFromCloudfrontRequest(\n    cloudFrontRequest: CloudFrontRequest,\n  ): SingleValueHeaders {\n    return Object.keys(cloudFrontRequest.headers).reduce((acc, headerKey) => {\n      const headerValue = cloudFrontRequest.headers[headerKey];\n\n      if (headerValue.length === 1) acc[headerKey] = headerValue[0].value;\n      else acc[headerKey] = headerValue.map(header => header.value).join(',');\n\n      return acc;\n    }, {} as SingleValueHeaders);\n  }\n\n  /**\n   * Returns headers in Cloudfront Response format.\n   *\n   * @param originalHeaders - The original version of the request sent by the framework\n   */\n  protected getHeadersForCloudfrontResponse(\n    originalHeaders: BothValueHeaders,\n  ): CloudFrontHeaders {\n    return Object.keys(originalHeaders).reduce((acc, headerKey) => {\n      if (this.shouldStripHeader(headerKey)) return acc;\n\n      const lowercaseHeaderKey = headerKey.toLowerCase();\n\n      if (!acc[lowercaseHeaderKey]) acc[lowercaseHeaderKey] = [];\n\n      const headerValue = originalHeaders[headerKey];\n\n      if (!Array.isArray(headerValue)) {\n        acc[lowercaseHeaderKey].push({\n          key: headerKey,\n          value: headerValue || '',\n        });\n\n        return acc;\n      }\n\n      const headersArray = headerValue.map(value => ({\n        key: headerKey,\n        value: value,\n      }));\n\n      acc[lowercaseHeaderKey].push(...headersArray);\n\n      return acc;\n    }, {} as CloudFrontHeaders);\n  }\n\n  /**\n   * Returns the information if we should remove the response header\n   *\n   * @param headerKey - The header that will be tested\n   */\n  protected shouldStripHeader(headerKey: string): boolean {\n    if (this.options?.shouldStripHeader)\n      return this.options.shouldStripHeader(headerKey);\n\n    const headerKeyLowerCase = headerKey.toLowerCase();\n\n    for (const stripHeaderIf of this.cachedDisallowedHeaders) {\n      if (!stripHeaderIf.test(headerKeyLowerCase)) continue;\n\n      return true;\n    }\n\n    return false;\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/aws/s3.adapter.ts",
    "content": "//#region Imports\n\nimport type { S3Event } from 'aws-lambda';\nimport { getDefaultIfUndefined } from '../../core';\nimport { AwsSimpleAdapter } from './base/index';\n\n//#endregion\n\n/**\n * The options to customize the {@link S3Adapter}\n *\n * @breadcrumb Adapters / AWS / S3Adapter\n * @public\n */\nexport interface S3AdapterOptions {\n  /**\n   * The path that will be used to create a request to be forwarded to the framework.\n   *\n   * @defaultValue /s3\n   */\n  s3ForwardPath?: string;\n\n  /**\n   * The http method that will be used to create a request to be forwarded to the framework.\n   *\n   * @defaultValue POST\n   */\n  s3ForwardMethod?: string;\n}\n\n/**\n * The adapter to handle requests from AWS S3.\n *\n * The option of `responseWithErrors` is ignored by this adapter and we always call `resolver.fail` with the error.\n *\n * {@link https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html | Event Reference}\n *\n * @example\n * ```typescript\n * const s3ForwardPath = '/your/route/s3'; // default /s3\n * const s3ForwardMethod = 'POST'; // default POST\n * const adapter = new S3Adapter({ s3ForwardPath, s3ForwardMethod });\n * ```\n *\n * @breadcrumb Adapters / AWS / S3Adapter\n * @public\n */\nexport class S3Adapter extends AwsSimpleAdapter<S3Event> {\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link SNSAdapter}\n   */\n  constructor(options?: S3AdapterOptions) {\n    super({\n      forwardPath: getDefaultIfUndefined(options?.s3ForwardPath, '/s3'),\n      forwardMethod: getDefaultIfUndefined(options?.s3ForwardMethod, 'POST'),\n      batch: false,\n      host: 's3.amazonaws.com',\n    });\n  }\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public override getAdapterName(): string {\n    return S3Adapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public override canHandle(event: unknown): event is S3Event {\n    const s3Event = event as Partial<S3Event>;\n\n    if (!Array.isArray(s3Event?.Records)) return false;\n\n    const eventSource = s3Event.Records[0]?.eventSource;\n\n    return eventSource === 'aws:s3';\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/aws/sns.adapter.ts",
    "content": "//#region Imports\n\nimport type { SNSEvent } from 'aws-lambda';\nimport { getDefaultIfUndefined } from '../../core';\nimport { AwsSimpleAdapter } from './base';\n\n//#endregion\n\n/**\n * The options to customize the {@link SNSAdapter}\n *\n * @breadcrumb Adapters / AWS / SNSAdapter\n * @public\n */\nexport interface SNSAdapterOptions {\n  /**\n   * The path that will be used to create a request to be forwarded to the framework.\n   *\n   * @defaultValue /sns\n   */\n  snsForwardPath?: string;\n\n  /**\n   * The http method that will be used to create a request to be forwarded to the framework.\n   *\n   * @defaultValue POST\n   */\n  snsForwardMethod?: string;\n}\n\n/**\n * The adapter to handle requests from AWS SNS.\n *\n * The option of `responseWithErrors` is ignored by this adapter and we always call `resolver.fail` with the error.\n *\n * {@link https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html | Event Reference}\n *\n * @example\n * ```typescript\n * const snsForwardPath = '/your/route/sns'; // default /sns\n * const snsForwardMethod = 'POST'; // default POST\n * const adapter = new SNSAdapter({ snsForwardPath, snsForwardMethod });\n * ```\n *\n * @breadcrumb Adapters / AWS / SNSAdapter\n * @public\n */\nexport class SNSAdapter extends AwsSimpleAdapter<SNSEvent> {\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link SNSAdapter}\n   */\n  constructor(options?: SNSAdapterOptions) {\n    super({\n      forwardPath: getDefaultIfUndefined(options?.snsForwardPath, '/sns'),\n      forwardMethod: getDefaultIfUndefined(options?.snsForwardMethod, 'POST'),\n      batch: false,\n      host: 'sns.amazonaws.com',\n    });\n  }\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public override getAdapterName(): string {\n    return SNSAdapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public override canHandle(event: unknown): event is SNSEvent {\n    const snsEvent = event as Partial<SNSEvent>;\n\n    if (!Array.isArray(snsEvent?.Records)) return false;\n\n    const eventSource = snsEvent.Records[0]?.EventSource;\n\n    return eventSource === 'aws:sns';\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/aws/sqs.adapter.ts",
    "content": "//#region Imports\n\nimport type { SQSEvent } from 'aws-lambda';\nimport { getDefaultIfUndefined } from '../../core';\nimport { type AWSSimpleAdapterOptions, AwsSimpleAdapter } from './base/index';\n\n//#endregion\n\n/**\n * The options to customize the {@link SQSAdapter}\n *\n * @breadcrumb Adapters / AWS / SQSAdapter\n * @public\n */\nexport interface SQSAdapterOptions\n  extends Pick<AWSSimpleAdapterOptions, 'batch'> {\n  /**\n   * The path that will be used to create a request to be forwarded to the framework.\n   *\n   * @defaultValue /sqs\n   */\n  sqsForwardPath?: string;\n\n  /**\n   * The http method that will be used to create a request to be forwarded to the framework.\n   *\n   * @defaultValue POST\n   */\n  sqsForwardMethod?: string;\n}\n\n/**\n * The adapter to handle requests from AWS SQS.\n *\n * The option of `responseWithErrors` is ignored by this adapter and we always call `resolver.fail` with the error.\n *\n * {@link https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html | Event Reference}\n *\n * @example\n * ```typescript\n * const sqsForwardPath = '/your/route/sqs'; // default /sqs\n * const sqsForwardMethod = 'POST'; // default POST\n * const adapter = new SQSAdapter({ sqsForwardPath, sqsForwardMethod });\n * ```\n *\n * @breadcrumb Adapters / AWS / SQSAdapter\n * @public\n */\nexport class SQSAdapter extends AwsSimpleAdapter<SQSEvent> {\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link SNSAdapter}\n   */\n  constructor(options?: SQSAdapterOptions) {\n    super({\n      forwardPath: getDefaultIfUndefined(options?.sqsForwardPath, '/sqs'),\n      forwardMethod: getDefaultIfUndefined(options?.sqsForwardMethod, 'POST'),\n      batch: options?.batch,\n      host: 'sqs.amazonaws.com',\n    });\n  }\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public override getAdapterName(): string {\n    return SQSAdapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public override canHandle(event: unknown): event is SQSEvent {\n    const sqsEvent = event as Partial<SQSEvent>;\n\n    if (!Array.isArray(sqsEvent?.Records)) return false;\n\n    const eventSource = sqsEvent.Records[0]?.eventSource;\n\n    return eventSource === 'aws:sqs';\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/azure/http-trigger-v4.adapter.ts",
    "content": "//#region Imports\n\nimport { URL } from 'node:url';\nimport type {\n  Context,\n  Cookie,\n  HttpRequest,\n  HttpResponseSimple,\n} from '@azure/functions';\nimport type { BothValueHeaders } from '../../@types';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  GetResponseAdapterProps,\n  OnErrorProps,\n} from '../../contracts';\nimport {\n  getDefaultIfUndefined,\n  getEventBodyAsBuffer,\n  getFlattenedHeadersMap,\n  getPathWithQueryStringParams,\n} from '../../core';\n\n//#endregion\n\n/**\n * The options to customize the {@link HttpTriggerV4Adapter}\n *\n * @breadcrumb Adapters / Azure / HttpTriggerV4Adapter\n * @public\n */\nexport interface HttpTriggerV4AdapterOptions {\n  /**\n   * Strip base path for custom domains\n   *\n   * @defaultValue ''\n   */\n  stripBasePath?: string;\n}\n\n/**\n * The adapter to handle requests from Http Trigger on Azure Function V4.\n *\n * @example\n * ```typescript\n * const stripBasePath = '/any/custom/base/path'; // default ''\n * const adapter = new HttpTriggerV4Adapter({ stripBasePath });\n * ```\n *\n * @see {@link https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node | Reference}\n *\n * @breadcrumb Adapters / Azure / HttpTriggerV4Adapter\n * @public\n */\nexport class HttpTriggerV4Adapter\n  implements AdapterContract<HttpRequest, Context, HttpResponseSimple>\n{\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link HttpTriggerV4Adapter}\n   */\n  constructor(protected readonly options?: HttpTriggerV4AdapterOptions) {}\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getAdapterName(): string {\n    return HttpTriggerV4Adapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public canHandle(event: unknown, context: unknown): boolean {\n    const maybeEvent = event as Partial<HttpRequest> | undefined;\n    const maybeContext = context as Partial<Context> | undefined;\n\n    return !!(\n      maybeEvent &&\n      maybeEvent.method &&\n      maybeEvent.headers &&\n      maybeEvent.url &&\n      maybeEvent.query &&\n      maybeContext &&\n      maybeContext.traceContext &&\n      maybeContext.bindingDefinitions &&\n      maybeContext.log &&\n      !!maybeContext.log.info &&\n      maybeContext.bindingData\n    );\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getRequest(event: HttpRequest): AdapterRequest {\n    const path = this.getPathFromEvent(event);\n\n    const method = event.method!;\n    const headers = getFlattenedHeadersMap(event.headers, ',', true);\n\n    let body: Buffer | undefined;\n\n    if (event.body) {\n      const [bufferBody, contentLength] = getEventBodyAsBuffer(\n        event.rawBody,\n        false,\n      );\n\n      body = bufferBody;\n      headers['content-length'] = String(contentLength);\n    }\n\n    const remoteAddress = headers['x-forwarded-for'];\n\n    return {\n      method,\n      path,\n      headers,\n      remoteAddress,\n      body,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getResponse({\n    body,\n    statusCode,\n    headers: originalHeaders,\n  }: GetResponseAdapterProps<HttpRequest>): HttpResponseSimple {\n    const headers = getFlattenedHeadersMap(originalHeaders, ',', true);\n    const cookies = this.getAzureCookiesFromHeaders(originalHeaders);\n\n    if (headers['set-cookie']) delete headers['set-cookie'];\n\n    return {\n      body,\n      statusCode,\n      headers,\n      // I tried to understand this property with\n      // https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/content-negotiation\n      // but I don't know if it's worth implementing this guy as an option\n      // I found out when this guy is set to true and the framework sets content-type, azure returns 500\n      // So I'll leave it as is and hope no one has any problems.\n      enableContentNegotiation: false,\n      cookies,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public onErrorWhileForwarding({\n    error,\n    respondWithErrors,\n    event,\n    delegatedResolver,\n    log,\n  }: OnErrorProps<HttpRequest, HttpResponseSimple>): void {\n    const body = respondWithErrors ? error.stack : '';\n    const errorResponse = this.getResponse({\n      event,\n      statusCode: 500,\n      body: body || '',\n      headers: {},\n      isBase64Encoded: false,\n      log,\n    });\n\n    delegatedResolver.succeed(errorResponse);\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Get path from event with query strings\n   *\n   * @param event - The event sent by serverless\n   */\n  protected getPathFromEvent(event: HttpRequest): string {\n    const stripBasePath = getDefaultIfUndefined(\n      this.options?.stripBasePath,\n      '',\n    );\n\n    const url = new URL(event.url);\n    const originalPath = url.pathname;\n\n    const replaceRegex = new RegExp(`^${stripBasePath}`);\n    const path = originalPath.replace(replaceRegex, '');\n\n    const queryParams = event.query;\n\n    return getPathWithQueryStringParams(path, queryParams);\n  }\n\n  /**\n   * Get the Azure Cookie list parsed from set-cookie header.\n   *\n   * @param headers - The headers object\n   */\n  protected getAzureCookiesFromHeaders(headers: BothValueHeaders): Cookie[] {\n    const setCookie = headers['set-cookie'];\n\n    const headerCookies = Array.isArray(setCookie)\n      ? setCookie\n      : setCookie\n        ? [setCookie]\n        : [];\n\n    return headerCookies.map(cookie => this.parseCookie(cookie));\n  }\n\n  /**\n   * Parse the string cookie to the Azure Cookie Object.\n   * This code was written by {@link https://github.com/zachabney | @zachabney}\n   * on {@link https://github.com/zachabney/azure-aws-serverless-express/blob/241d2d5c4d5906e4817662cad6426ec2cbbf9ca7/src/index.js#L4-L49 | this library}.\n   *\n   * @param cookie - The cookie\n   */\n  protected parseCookie(cookie: string): Cookie {\n    return cookie.split(';').reduce(\n      (azureCookieObject, cookieProperty, index) => {\n        const [key, value] = cookieProperty.split('=');\n\n        const sanitizedKey = key.toLowerCase().trim();\n        const sanitizedValue = value && value.trim();\n\n        if (index === 0) {\n          azureCookieObject.name = key;\n          azureCookieObject.value = sanitizedValue;\n\n          return azureCookieObject;\n        }\n\n        switch (sanitizedKey) {\n          case 'domain':\n            azureCookieObject.domain = sanitizedValue;\n            break;\n          case 'path':\n            azureCookieObject.path = sanitizedValue;\n            break;\n          case 'expires':\n            azureCookieObject.expires = new Date(sanitizedValue);\n            break;\n          case 'secure':\n            azureCookieObject.secure = true;\n            break;\n          case 'httponly':\n            azureCookieObject.httpOnly = true;\n            break;\n          case 'samesite':\n            azureCookieObject.sameSite = sanitizedValue as Cookie['sameSite'];\n            break;\n          case 'max-age':\n            azureCookieObject.maxAge = Number(sanitizedValue);\n            break;\n        }\n\n        return azureCookieObject;\n      },\n      { name: '', value: '' } as Cookie,\n    );\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/azure/index.ts",
    "content": "export * from './http-trigger-v4.adapter';\n"
  },
  {
    "path": "src/adapters/digital-ocean/http-function.adapter.ts",
    "content": "//#region Imports\n\n//#region Imports\n\nimport type {\n  DigitalOceanHttpEvent,\n  DigitalOceanHttpResponse,\n} from '../../@types/digital-ocean';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  GetResponseAdapterProps,\n  OnErrorProps,\n} from '../../contracts';\nimport {\n  getDefaultIfUndefined,\n  getEventBodyAsBuffer,\n  getFlattenedHeadersMap,\n  getPathWithQueryStringParams,\n} from '../../core';\n\n//#endregion\n\n/**\n * The options to customize the {@link HttpFunctionAdapter}\n *\n * @breadcrumb Adapters / Digital Ocean / HttpFunctionAdapter\n * @public\n */\nexport interface HttpFunctionAdapterOptions {\n  /**\n   * Strip base path for custom domains\n   *\n   * @defaultValue ''\n   */\n  stripBasePath?: string;\n}\n\n/**\n * The adapter to handle requests from Digital Ocean Functions when called from HTTP Endpoint.\n *\n * @example\n * ```typescript\n * const stripBasePath = '/any/custom/base/path'; // default ''\n * const adapter = new HttpFunctionAdapter({ stripBasePath });\n * ```\n *\n * @breadcrumb Adapters / Digital Ocean / HttpFunctionAdapter\n * @public\n */\nexport class HttpFunctionAdapter\n  implements\n    AdapterContract<DigitalOceanHttpEvent, void, DigitalOceanHttpResponse>\n{\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link HttpFunctionAdapter}\n   */\n  constructor(protected readonly options?: HttpFunctionAdapterOptions) {}\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getAdapterName(): string {\n    return HttpFunctionAdapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public canHandle(event: unknown): event is DigitalOceanHttpEvent {\n    const digitalOceanHttpEvent = event as DigitalOceanHttpEvent;\n\n    return (\n      !!digitalOceanHttpEvent &&\n      digitalOceanHttpEvent.__ow_path !== undefined &&\n      digitalOceanHttpEvent.__ow_method !== undefined &&\n      digitalOceanHttpEvent.__ow_headers !== undefined\n    );\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getRequest(event: DigitalOceanHttpEvent): AdapterRequest {\n    const headers = event.__ow_headers;\n    const method = event.__ow_method.toUpperCase();\n    const path = this.getPathFromEvent(event);\n\n    let body: Buffer | undefined;\n\n    if (event.__ow_body) {\n      const [bufferBody, contentLength] = getEventBodyAsBuffer(\n        event.__ow_body,\n        !!event.__ow_isBase64Encoded,\n      );\n\n      body = bufferBody;\n      headers['content-length'] = String(contentLength);\n    }\n\n    const remoteAddress = headers['x-forwarded-for'];\n\n    return {\n      method,\n      headers,\n      body,\n      remoteAddress,\n      path,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getResponse({\n    headers: responseHeaders,\n    body,\n    statusCode,\n  }: GetResponseAdapterProps<DigitalOceanHttpEvent>): DigitalOceanHttpResponse {\n    const headers = getFlattenedHeadersMap(responseHeaders);\n\n    return {\n      statusCode,\n      body,\n      headers,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public onErrorWhileForwarding({\n    error,\n    delegatedResolver,\n    respondWithErrors,\n    event,\n    log,\n  }: OnErrorProps<DigitalOceanHttpEvent, DigitalOceanHttpResponse>): void {\n    const body = respondWithErrors ? error.stack : '';\n    const errorResponse = this.getResponse({\n      event,\n      statusCode: 500,\n      body: body || '',\n      headers: {},\n      isBase64Encoded: false,\n      log,\n    });\n\n    delegatedResolver.succeed(errorResponse);\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Get path from event with query strings\n   *\n   * @param event - The event sent by digital ocean\n   */\n  protected getPathFromEvent(event: DigitalOceanHttpEvent): string {\n    const stripBasePath = getDefaultIfUndefined(\n      this.options?.stripBasePath,\n      '',\n    );\n    const replaceRegex = new RegExp(`^${stripBasePath}`);\n\n    const path = event.__ow_path.replace(replaceRegex, '');\n    const queryParams = event.__ow_query;\n\n    return getPathWithQueryStringParams(path, queryParams || {});\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/digital-ocean/index.ts",
    "content": "export * from './http-function.adapter';\n"
  },
  {
    "path": "src/adapters/dummy/dummy.adapter.ts",
    "content": "//#region Imports\n\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  OnErrorProps,\n} from '../../contracts';\nimport { EmptyResponse, type IEmptyResponse } from '../../core';\n\n//#endregion\n\n/**\n * The class that represents a dummy adapter that does nothing and can be used by the cloud that doesn't use adapters.\n *\n * @breadcrumb Adapters / DummyAdapter\n * @public\n */\nexport class DummyAdapter implements AdapterContract<any, any, void> {\n  /**\n   * {@inheritDoc}\n   */\n  public canHandle(): boolean {\n    return true;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getAdapterName(): string {\n    return DummyAdapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getRequest(): AdapterRequest {\n    return {\n      method: 'POST',\n      body: void 0,\n      path: '/dummy',\n      headers: {},\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getResponse(): IEmptyResponse {\n    return EmptyResponse;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public onErrorWhileForwarding(props: OnErrorProps<any, void>): void {\n    props.delegatedResolver.succeed();\n  }\n}\n"
  },
  {
    "path": "src/adapters/dummy/index.ts",
    "content": "export * from './dummy.adapter';\n"
  },
  {
    "path": "src/adapters/huawei/huawei-api-gateway.adapter.ts",
    "content": "//#region Imports\n\nimport type {\n  HuaweiApiGatewayEvent,\n  HuaweiApiGatewayResponse,\n  HuaweiContext,\n} from '../../@types/huawei';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  GetResponseAdapterProps,\n  OnErrorProps,\n} from '../../contracts';\nimport {\n  getDefaultIfUndefined,\n  getEventBodyAsBuffer,\n  getFlattenedHeadersMap,\n  getMultiValueHeadersMap,\n  getPathWithQueryStringParams,\n} from '../../core';\n\n//#endregion\n\n/**\n * The options to customize the {@link HuaweiApiGatewayAdapter}\n *\n * @breadcrumb Adapters / Huawei / HuaweiApiGatewayAdapter\n * @public\n */\nexport interface HuaweiApiGatewayOptions {\n  /**\n   * Strip base path for custom domains\n   *\n   * @defaultValue ''\n   */\n  stripBasePath?: string;\n}\n\n/**\n * The adapter to handle requests from Huawei Api Gateway\n *\n * @example\n * ```typescript\n * const stripBasePath = '/any/custom/base/path'; // default ''\n * const adapter = new ApiGatewayAdapter({ stripBasePath });\n * ```\n *\n * @breadcrumb Adapters / Huawei / HuaweiApiGatewayAdapter\n * @public\n *\n * {@link https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0102.html#functiongraph_02_0102__li5178638110137 | Event Reference}\n */\nexport class HuaweiApiGatewayAdapter\n  implements\n    AdapterContract<\n      HuaweiApiGatewayEvent,\n      HuaweiContext,\n      HuaweiApiGatewayResponse\n    >\n{\n  //#region Constructor\n\n  /**\n   * Default constructor\n   *\n   * @param options - The options to customize the {@link HuaweiApiGatewayAdapter}\n   */\n  constructor(protected readonly options?: HuaweiApiGatewayOptions) {}\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getAdapterName(): string {\n    return HuaweiApiGatewayAdapter.name;\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public canHandle(event: unknown): event is HuaweiApiGatewayEvent {\n    const apiGatewayEvent = event as Partial<HuaweiApiGatewayEvent>;\n\n    return !!(\n      apiGatewayEvent &&\n      apiGatewayEvent.httpMethod &&\n      apiGatewayEvent.requestContext &&\n      apiGatewayEvent.requestContext.apiId &&\n      apiGatewayEvent.requestContext.stage &&\n      apiGatewayEvent.requestContext.requestId &&\n      // to avoid conflict with api gateway v1 of aws\n      !('multiValueQueryStringParameters' in apiGatewayEvent)\n    );\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getRequest(event: HuaweiApiGatewayEvent): AdapterRequest {\n    const method = event.httpMethod;\n    const path = this.getPathFromEvent(event);\n\n    const headers = getFlattenedHeadersMap(event.headers, ',', true);\n\n    let body: Buffer | undefined;\n\n    if (event.body) {\n      const [bufferBody, contentLength] = getEventBodyAsBuffer(\n        event.body,\n        event.isBase64Encoded,\n      );\n\n      body = bufferBody;\n      headers['content-length'] = String(contentLength);\n    }\n\n    const remoteAddress = headers['x-real-ip'];\n\n    return {\n      method,\n      headers,\n      body,\n      remoteAddress,\n      path,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public getResponse({\n    headers: responseHeaders,\n    body,\n    isBase64Encoded,\n    statusCode,\n  }: GetResponseAdapterProps<HuaweiApiGatewayEvent>): HuaweiApiGatewayResponse {\n    const headers = getMultiValueHeadersMap(responseHeaders);\n\n    return {\n      statusCode,\n      body,\n      headers,\n      isBase64Encoded,\n    };\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public onErrorWhileForwarding({\n    error,\n    delegatedResolver,\n    respondWithErrors,\n    event,\n    log,\n  }: OnErrorProps<HuaweiApiGatewayEvent, HuaweiApiGatewayResponse>): void {\n    const body = respondWithErrors ? error.stack : '';\n    const errorResponse = this.getResponse({\n      event,\n      statusCode: 500,\n      body: body || '',\n      headers: {},\n      isBase64Encoded: false,\n      log,\n    });\n\n    delegatedResolver.succeed(errorResponse);\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Get path from event with query strings\n   *\n   * @param event - The event sent by serverless\n   */\n  protected getPathFromEvent(event: HuaweiApiGatewayEvent): string {\n    const stripBasePath = getDefaultIfUndefined(\n      this.options?.stripBasePath,\n      '',\n    );\n    const replaceRegex = new RegExp(`^${stripBasePath}`);\n    const path = event.path.replace(replaceRegex, '');\n\n    const queryParams = event.queryStringParameters;\n\n    return getPathWithQueryStringParams(path, queryParams);\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/adapters/huawei/index.ts",
    "content": "export * from './huawei-api-gateway.adapter';\n"
  },
  {
    "path": "src/contracts/adapter.contract.ts",
    "content": "//#region Imports\n\nimport type { BothValueHeaders, SingleValueHeaders } from '../@types';\nimport type { ILogger } from '../core';\nimport { ServerlessResponse } from '../network';\nimport type { DelegatedResolver } from './resolver.contract';\n\n//#endregion\n\n/**\n * The request interface used to bridge any event source to the framework.\n *\n * @breadcrumb Contracts / AdapterContract\n * @public\n */\nexport interface AdapterRequest {\n  /**\n   * The HTTP Method to use to create the request to the framework\n   */\n  method: string;\n\n  /**\n   * The path to use to create the request to the framework\n   */\n  path: string;\n\n  /**\n   * The headers to use to create the request to the framework\n   */\n  headers: SingleValueHeaders;\n\n  /**\n   * The body as buffer to use to create the request to the framework\n   */\n  body?: Buffer;\n\n  /**\n   * The remote address (client ip) to use to create the request to the framework\n   */\n  remoteAddress?: string;\n\n  /**\n   * The address of the event source (used in Lambda\\@edge)\n   *\n   * @deprecated It is no longer used in the library and will be removed in the next major release.\n   */\n  host?: string;\n\n  /**\n   * The address of the event source (used in Lambda\\@edge)\n   *\n   * @deprecated It is no longer used in the library and will be removed in the next major release.\n   */\n  hostname?: string;\n}\n\n/**\n * The props of the method that get the response from the framework and transform it into a format that the event source can handle\n *\n * @breadcrumb Contracts / AdapterContract\n * @public\n */\nexport interface GetResponseAdapterProps<TEvent> {\n  /**\n   * The event sent by the serverless\n   */\n  event: TEvent;\n\n  /**\n   * The framework {@link ServerlessResponse | response}.\n   *\n   * @remarks It can be optional, as this method can be used when an error occurs during the handling of the request by the framework.\n   */\n  response?: ServerlessResponse;\n\n  /**\n   * The framework response status code\n   */\n  statusCode: number;\n\n  /**\n   * The framework response body\n   */\n  body: string;\n\n  /**\n   * The framework response headers\n   */\n  headers: BothValueHeaders;\n\n  /**\n   * Indicates whether the response is base64 encoded or not\n   */\n  isBase64Encoded: boolean;\n\n  /**\n   * The instance of the logger\n   */\n  log: ILogger;\n}\n\n/**\n * The props of the method that handle the response when an error occurs while forwarding the request to the framework\n *\n * @breadcrumb Contracts / AdapterContract\n * @public\n */\nexport interface OnErrorProps<TEvent, TResponse> {\n  /**\n   * The event sent by the serverless\n   */\n  event: TEvent;\n\n  /**\n   * The error throwed during forwarding\n   */\n  error: Error;\n\n  /**\n   * The instance of the resolver\n   */\n  delegatedResolver: DelegatedResolver<TResponse>;\n\n  /**\n   * Indicates whether to forward the (error.stack) or not to the client\n   */\n  respondWithErrors: boolean;\n\n  /**\n   * The instance of the logger\n   */\n  log: ILogger;\n}\n\n/**\n * The interface that represents a contract between the adapter and the actual implementation of the adapter.\n *\n * @breadcrumb Contracts / AdapterContract\n * @public\n */\nexport interface AdapterContract<TEvent, TContext, TResponse> {\n  /**\n   * Get the adapter name\n   */\n  getAdapterName(): string;\n\n  /**\n   * Decide if this adapter can handle a request based in the event payload\n   *\n   * @param event - The event sent by serverless\n   * @param context - The context sent by the serverless\n   * @param log - The instance of logger\n   */\n  canHandle(event: unknown, context: TContext, log: ILogger): boolean;\n\n  /**\n   * Maps the serverless payload to an actual request that a framework can handle\n   *\n   * @param event - The event sent by serverless\n   * @param context - The context sent by the serverless\n   * @param log - The instance of logger\n   */\n  getRequest(event: TEvent, context: TContext, log: ILogger): AdapterRequest;\n\n  /**\n   * Maps the response of the framework to a payload that serverless can handle\n   *\n   * @param props - The props sent by serverless\n   */\n  getResponse(props: GetResponseAdapterProps<TEvent>): TResponse;\n\n  /**\n   * When an error occurs while forwarding the request to the framework\n   *\n   * @remarks You must call resolver.fail or resolver.succeed when implementing this method.\n   */\n  onErrorWhileForwarding(props: OnErrorProps<TEvent, TResponse>): void;\n}\n"
  },
  {
    "path": "src/contracts/framework.contract.ts",
    "content": "//#region Imports\n\nimport type { IncomingMessage, ServerResponse } from 'http';\n\n//#endregion\n\n/**\n * The interface that represents a contract between the framework and the framework implementation\n *\n * @breadcrumb Contracts\n * @public\n */\nexport interface FrameworkContract<TApp> {\n  /**\n   * Send the request and response objects to the framework\n   *\n   * @param app - The instance of your app (Express, Fastify, Koa, etc...)\n   * @param request - The request object that will be forward to your app\n   * @param response - The response object that will be forward to your app to output the response\n   */\n  sendRequest(\n    app: TApp,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): void;\n}\n"
  },
  {
    "path": "src/contracts/handler.contract.ts",
    "content": "//#region Imports\n\nimport type { BinarySettings } from '../@types';\nimport type { ILogger } from '../core';\nimport type { AdapterContract } from './adapter.contract';\nimport type { FrameworkContract } from './framework.contract';\nimport type { ResolverContract } from './resolver.contract';\n\n//#endregion\n\n/**\n * The function used to handle serverless requests\n *\n * @breadcrumb Contracts / HandlerContract\n * @public\n */\nexport type ServerlessHandler<TReturn> = (...args: any[]) => TReturn;\n\n/**\n * The interface that represents the contract between the handler and the real implementation\n *\n * @breadcrumb Contracts / HandlerContract\n * @public\n */\nexport interface HandlerContract<\n  TApp,\n  TEvent,\n  TContext,\n  TCallback,\n  TResponse,\n  TReturn,\n> {\n  /**\n   * Get the handler that will handle serverless requests\n   */\n  getHandler(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n    adapters: AdapterContract<TEvent, TContext, TResponse>[],\n    resolverFactory: ResolverContract<\n      TEvent,\n      TContext,\n      TCallback,\n      TResponse,\n      TReturn\n    >,\n    binarySettings: BinarySettings,\n    respondWithErrors: boolean,\n    log: ILogger,\n  ): ServerlessHandler<TReturn>;\n}\n"
  },
  {
    "path": "src/contracts/index.ts",
    "content": "export * from './adapter.contract';\nexport * from './framework.contract';\nexport * from './handler.contract';\nexport * from './resolver.contract';\n"
  },
  {
    "path": "src/contracts/resolver.contract.ts",
    "content": "//#region Imports\n\nimport type { ILogger } from '../core';\nimport type { AdapterContract } from './adapter.contract';\n\n//#endregion\n\n/**\n * The type that represents a resolver used to send the response, error or success, to the client\n *\n * @breadcrumb Contracts / ResolverContract\n * @public\n */\nexport type Resolver<TResponse, TReturn> = {\n  /**\n   * The method that will perform the task of forwarding the request to the framework and waiting for the promise to be resolved with the response\n   *\n   * @param task - The task to be executed\n   */\n  run(task: () => Promise<TResponse>): TReturn;\n};\n\n/**\n * The type that represents a delegate resolver that is passed to the adapter to handle what to do when an error occurs during forwarding.\n *\n * @breadcrumb Contracts / ResolverContract\n * @public\n */\nexport type DelegatedResolver<TResponse> = {\n  /**\n   * Send the success response to the client\n   *\n   * @param success - The serverless response\n   */\n  succeed: (response: TResponse) => void;\n\n  /**\n   * Send the error response to the client\n   *\n   * @param error - The error object\n   */\n  fail: (error: Error) => void;\n};\n\n/**\n * The createResolver contract props\n *\n * @breadcrumb Contracts / ResolverContract\n * @public\n */\nexport type ResolverProps<TEvent, TContext, TCallback, TResponse> = {\n  /**\n   * The event sent by the serverless environment\n   */\n  event: TEvent;\n\n  /**\n   * Indicates whether to forward the (error.stack) or not to the client\n   */\n  respondWithErrors: boolean;\n\n  /**\n   * The instance of the logger\n   */\n  log: ILogger;\n\n  /**\n   * The instance of the adapter\n   */\n  adapter: AdapterContract<TEvent, TContext, TResponse>;\n\n  /**\n   * The context sent by serverless\n   */\n  context?: TContext;\n\n  /**\n   * The callback sent by serverless\n   */\n  callback?: TCallback;\n};\n\n/**\n * The interface that represents the contract used to send the response to the client\n *\n * @breadcrumb Contracts / ResolverContract\n * @public\n */\nexport interface ResolverContract<\n  TEvent,\n  TContext,\n  TCallback,\n  TResponse,\n  TReturn,\n> {\n  /**\n   * Create the resolver based on the context, callback or promise\n   *\n   * @param props - The props used to create the resolver\n   */\n  createResolver(\n    props: ResolverProps<TEvent, TContext, TCallback, TResponse>,\n  ): Resolver<TResponse, TReturn>;\n}\n"
  },
  {
    "path": "src/core/base-handler.ts",
    "content": "//#region Imports\n\nimport type { BinarySettings } from '../@types';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  FrameworkContract,\n  HandlerContract,\n  ResolverContract,\n  ServerlessHandler,\n} from '../contracts';\nimport { ServerlessRequest, ServerlessResponse } from '../network';\nimport type { ILogger } from './index';\n\n//#endregion\n\n/**\n * The abstract class that represents the base class for a handler\n *\n * @breadcrumb Core\n * @public\n */\nexport abstract class BaseHandler<\n  TApp,\n  TEvent,\n  TContext,\n  TCallback,\n  TResponse,\n  TReturn,\n> implements\n    HandlerContract<TApp, TEvent, TContext, TCallback, TResponse, TReturn>\n{\n  //#region Public Methods\n\n  /**\n   * Get the handler that will handle serverless requests\n   */\n  public abstract getHandler(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n    adapters: AdapterContract<TEvent, TContext, TResponse>[],\n    resolverFactory: ResolverContract<\n      TEvent,\n      TContext,\n      TCallback,\n      TResponse,\n      TReturn\n    >,\n    binarySettings: BinarySettings,\n    respondWithErrors: boolean,\n    log: ILogger,\n  ): ServerlessHandler<TReturn>;\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Get the adapter to handle a specific event and context\n   *\n   * @param event - The event sent by serverless\n   * @param context - The context sent by serverless\n   * @param adapters - The list of adapters\n   * @param log - The instance of logger\n   */\n  protected getAdapterByEventAndContext(\n    event: TEvent,\n    context: TContext,\n    adapters: AdapterContract<TEvent, TContext, TResponse>[],\n    log: ILogger,\n  ): AdapterContract<TEvent, TContext, TResponse> {\n    const resolvedAdapters = adapters.filter(adapter =>\n      adapter.canHandle(event, context, log),\n    );\n\n    if (resolvedAdapters.length === 0) {\n      throw new Error(\n        \"SERVERLESS_ADAPTER: Couldn't find adapter to handle this event.\",\n      );\n    }\n\n    if (resolvedAdapters.length > 1) {\n      throw new Error(\n        `SERVERLESS_ADAPTER: Two or more adapters was resolved by the event, the adapters are: ${adapters\n          .map(adapter => adapter.getAdapterName())\n          .join(', ')}.`,\n      );\n    }\n\n    return resolvedAdapters[0];\n  }\n\n  /**\n   * Get serverless request and response frmo the adapter request\n   *\n   * @param requestValues - The request values from adapter\n   */\n  protected getServerlessRequestResponseFromAdapterRequest(\n    requestValues: AdapterRequest,\n  ): [request: ServerlessRequest, response: ServerlessResponse] {\n    const request = new ServerlessRequest({\n      method: requestValues.method,\n      headers: requestValues.headers,\n      body: requestValues.body,\n      remoteAddress: requestValues.remoteAddress,\n      url: requestValues.path,\n    });\n\n    const response = new ServerlessResponse({\n      method: requestValues.method,\n    });\n\n    return [request, response];\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/core/constants.ts",
    "content": "/**\n * Default encodings that are treated as binary, they are compared with the `Content-Encoding` header.\n *\n * @breadcrumb Core / Constants\n * @defaultValue ['gzip', 'deflate', 'br']\n * @public\n */\nexport const DEFAULT_BINARY_ENCODINGS: string[] = ['gzip', 'deflate', 'br'];\n\n/**\n * Default content types that are treated as binary, they are compared with the `Content-Type` header.\n *\n * @breadcrumb Core / Constants\n * @defaultValue ['image/png', 'image/jpeg', 'image/jpg', 'image/avif', 'image/bmp', 'image/x-png', 'image/gif', 'image/webp', 'video/mp4', 'application/pdf']\n * @public\n */\nexport const DEFAULT_BINARY_CONTENT_TYPES: string[] = [\n  'image/png',\n  'image/jpeg',\n  'image/jpg',\n  'image/avif',\n  'image/bmp',\n  'image/x-png',\n  'image/gif',\n  'image/webp',\n  'video/mp4',\n  'application/pdf',\n];\n\n/**\n * Type alias for empty response and can be used on some adapters when the adapter does not need to return a response.\n *\n * @breadcrumb Core / Constants\n * @public\n */\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport type IEmptyResponse = {};\n\n/**\n * Constant for empty response and can be used on some adapters when the adapter does not need to return a response.\n *\n * @breadcrumb Core / Constants\n * @public\n */\nexport const EmptyResponse: IEmptyResponse = {};\n"
  },
  {
    "path": "src/core/current-invoke.ts",
    "content": "/**\n * The type that represents the object that handles the references to the event created by the serverless trigger or context created by the serverless environment.\n *\n * @breadcrumb Core / Current Invoke\n * @public\n */\nexport type CurrentInvoke<TEvent, TContext> = {\n  /**\n   * The event created by the serverless trigger\n   *\n   * @remarks It's only null when you call {@link getCurrentInvoke} outside this library's pipeline.\n   */\n  event: TEvent | null;\n\n  /**\n   * The context created by the serverless environment\n   *\n   * @remarks It's only null when you call {@link getCurrentInvoke} outside this library's pipeline.\n   */\n  context: TContext | null;\n};\n\nconst currentInvoke: CurrentInvoke<any, any> = {\n  context: null,\n  event: null,\n};\n\n/**\n * Get the reference to the event created by the serverless trigger or context created by the serverless environment.\n *\n * @example\n * ```typescript\n * import type { ALBEvent, Context } from 'aws-lambda';\n *\n * // inside the method that handles the aws alb request.\n * const { event, context } = getCurrentInvoke<ALBEvent, Context>();\n * ```\n *\n * @breadcrumb Core / Current Invoke\n * @public\n */\nexport function getCurrentInvoke<TEvent = any, TContext = any>(): CurrentInvoke<\n  TEvent,\n  TContext\n> {\n  return currentInvoke;\n}\n\n/**\n * Method that saves to the event created by the serverless trigger or context created by the serverless environment.\n *\n * @remarks This method MUST NOT be called by you, this method MUST only be used internally in this library.\n *\n * @param event - The event created by the serverless trigger\n * @param context - The context created by the serverless environment\n *\n * @breadcrumb Core / Current Invoke\n * @public\n */\nexport function setCurrentInvoke<TEvent = any, TContext = any>({\n  event,\n  context,\n}: CurrentInvoke<TEvent, TContext>) {\n  currentInvoke.event = event;\n  currentInvoke.context = context;\n}\n"
  },
  {
    "path": "src/core/event-body.ts",
    "content": "/**\n * Get the event body as buffer from body string with content length\n *\n * @example\n * ```typescript\n * const body = '{}';\n * const [buffer, contentLength] = getEventBodyAsBuffer(body, false);\n * console.log(buffer);\n * // <Buffer 7b 7d>\n * console.log(contentLength);\n * // 2\n * ```\n *\n * @param body - The body string that can be encoded or not\n * @param isBase64Encoded - Tells if body string is encoded in base64\n *\n * @breadcrumb Core\n * @public\n */\nexport function getEventBodyAsBuffer(\n  body: string,\n  isBase64Encoded: boolean,\n): [body: Buffer, contentLength: number] {\n  const encoding: BufferEncoding = isBase64Encoded ? 'base64' : 'utf8';\n\n  const buffer = Buffer.from(body, encoding);\n  const contentLength = Buffer.byteLength(buffer, encoding);\n\n  return [buffer, contentLength];\n}\n"
  },
  {
    "path": "src/core/headers.ts",
    "content": "//#region Imports\n\nimport type { BothValueHeaders } from '../@types';\n\n//#endregion\n\n/**\n * Transform a header map and make sure the value is not an array\n *\n * @example\n * ```typescript\n * const headers = { 'accept-encoding': 'gzip', 'accept-language': ['en-US', 'en;q=0.9'] };\n * const flattenedHeaders = getFlattenedHeadersMap(headers, ',', true);\n * console.log(flattenedHeaders);\n * // { 'accept-encoding': 'gzip', 'accept-language': 'en-US,en;q=0.9' }\n * ```\n *\n * @param headersMap - The initial headers\n * @param separator - The separator used when we join the array of header's value\n * @param lowerCaseKey - Should put all keys in lowercase\n *\n * @breadcrumb Core / Headers\n * @public\n */\nexport function getFlattenedHeadersMap(\n  headersMap: BothValueHeaders,\n  separator: string = ',',\n  lowerCaseKey: boolean = false,\n): Record<string, string> {\n  return Object.keys(headersMap).reduce((acc, headerKey) => {\n    const newKey = lowerCaseKey ? headerKey.toLowerCase() : headerKey;\n    const headerValue = headersMap[headerKey];\n\n    if (Array.isArray(headerValue)) acc[newKey] = headerValue.join(separator);\n    else acc[newKey] = (headerValue ?? '') + '';\n\n    return acc;\n  }, {});\n}\n\n/**\n * Transforms a header map into a multi-value map header.\n *\n * @example\n * ```typescript\n * const headers = { 'accept-encoding': 'gzip', 'connection': ['keep-alive'] };\n * const multiValueHeaders = getMultiValueHeadersMap(headers);\n * console.log(multiValueHeaders);\n * // { 'accept-encoding': ['gzip'], 'connection': ['keep-alive'] }\n * ```\n *\n * @param headersMap - The initial headers\n *\n * @breadcrumb Core / Headers\n * @public\n */\nexport function getMultiValueHeadersMap(\n  headersMap: BothValueHeaders,\n): Record<string, string[]> {\n  return Object.keys(headersMap).reduce((acc, headerKey) => {\n    const headerValue = headersMap[headerKey];\n\n    acc[headerKey.toLowerCase()] = Array.isArray(headerValue)\n      ? headerValue.map(String)\n      : [String(headerValue)];\n\n    return acc;\n  }, {});\n}\n\n/**\n * The wrapper that holds the information about single value headers and cookies\n *\n * @breadcrumb Core / Headers\n * @public\n */\nexport type FlattenedHeadersAndCookies = {\n  /**\n   * Just the single value headers\n   */\n  headers: Record<string, string>;\n\n  /**\n   * The list of cookies\n   */\n  cookies: string[];\n};\n\n/**\n * Transforms a header map into a single value headers and cookies\n *\n * @param headersMap - The initial headers\n *\n * @breadcrumb Core / Headers\n * @public\n */\nexport function getFlattenedHeadersMapAndCookies(\n  headersMap: BothValueHeaders,\n): FlattenedHeadersAndCookies {\n  return Object.keys(headersMap).reduce(\n    (acc, headerKey) => {\n      const headerValue = headersMap[headerKey];\n      const lowerHeaderKey = headerKey.toLowerCase();\n\n      if (Array.isArray(headerValue)) {\n        if (lowerHeaderKey !== 'set-cookie')\n          acc.headers[headerKey] = headerValue.join(',');\n        else acc.cookies.push(...headerValue);\n      } else {\n        if (lowerHeaderKey === 'set-cookie' && headerValue !== undefined)\n          acc.cookies.push(headerValue ?? '');\n        else acc.headers[headerKey] = String(headerValue ?? '');\n      }\n\n      return acc;\n    },\n    {\n      cookies: [],\n      headers: {},\n    } as FlattenedHeadersAndCookies,\n  );\n}\n\n/**\n * Parse HTTP Raw Headers\n * Attribution to {@link https://github.com/kesla/parse-headers/blob/master/parse-headers.js}\n *\n * @param headers - The raw headers\n *\n * @breadcrumb Core / Headers\n * @public\n */\nexport function parseHeaders(\n  headers: string,\n): Record<string, string | string[]> {\n  if (!headers) return {};\n\n  const result = {};\n  const headersArr = headers.trim().split('\\n');\n\n  for (let i = 0; i < headersArr.length; i++) {\n    const row = headersArr[i];\n    const index = row.indexOf(':');\n    const key = row.slice(0, index).trim().toLowerCase();\n    const value = row.slice(index + 1).trim();\n\n    if (typeof result[key] === 'undefined') result[key] = value;\n    else if (Array.isArray(result[key])) result[key].push(value);\n    else result[key] = [result[key], value];\n  }\n\n  return result;\n}\n\nexport function keysToLowercase<T extends Record<string, unknown>>(\n  obj: T,\n): { [K in keyof T as Lowercase<string & K>]: T[K] } {\n  const result: any = {};\n  for (const [k, v] of Object.entries(obj)) result[k.toLowerCase()] = v;\n\n  return result as { [K in keyof T as Lowercase<string & K>]: T[K] };\n}\n"
  },
  {
    "path": "src/core/index.ts",
    "content": "export * from './base-handler';\nexport * from './constants';\nexport * from './current-invoke';\nexport * from './event-body';\nexport * from './headers';\nexport * from './is-binary';\nexport * from './logger';\nexport * from './no-op';\nexport * from './optional';\nexport * from './path';\nexport * from './stream';\n"
  },
  {
    "path": "src/core/is-binary.ts",
    "content": "// ATTRIBUTION: https://github.com/dougmoscrop/serverless-http\n\n//#region Imports\n\nimport type { BinarySettings, BothValueHeaders } from '../@types';\n\n//#endregion\n\n/**\n * The function that determines by the content encoding whether the response should be treated as binary\n *\n * @example\n * ```typescript\n * const headers = { 'content-encoding': 'gzip' };\n * const isBinary = isContentEncodingBinary(headers, ['gzip']);\n * console.log(isBinary);\n * // true\n * ```\n *\n * @param headers - The headers of the response\n * @param binaryEncodingTypes - The list of content encodings that will be treated as binary\n *\n * @breadcrumb Core / isBinary\n * @public\n */\nexport function isContentEncodingBinary(\n  headers: BothValueHeaders,\n  binaryEncodingTypes: string[],\n): boolean {\n  let contentEncodings = headers['content-encoding'];\n\n  if (!contentEncodings) return false;\n\n  if (!Array.isArray(contentEncodings))\n    contentEncodings = contentEncodings.split(',');\n\n  return contentEncodings.some(value =>\n    binaryEncodingTypes.includes(value.trim()),\n  );\n}\n\n/**\n * The function that returns the content type of headers\n *\n * @example\n * ```typescript\n * const headers = { 'content-type': 'application/json' };\n * const contentType = getContentType(headers);\n * console.log(contentType);\n * // application/json\n * ```\n *\n * @param headers - The headers of the response\n *\n * @breadcrumb Core / isBinary\n * @public\n */\nexport function getContentType(headers: BothValueHeaders): string {\n  const contentTypeHeaderRaw = headers['content-type'];\n  const contentTypeHeader = Array.isArray(contentTypeHeaderRaw)\n    ? contentTypeHeaderRaw[0] || ''\n    : contentTypeHeaderRaw || '';\n\n  if (!contentTypeHeaderRaw) return '';\n\n  // only compare mime type; ignore encoding part\n  const contentTypeStart = contentTypeHeader.indexOf(';');\n\n  if (contentTypeStart === -1) return contentTypeHeader;\n\n  return contentTypeHeader.slice(0, contentTypeStart);\n}\n\n/**\n * The function that determines by the content type whether the response should be treated as binary\n *\n * @example\n * ```typescript\n * const headers = { 'content-type': 'image/png' };\n * const isBinary = isContentTypeBinary(headers, new Map([['image/png', true]]));\n * console.log(isBinary);\n * // true\n * ```\n *\n * @param headers - The headers of the response\n * @param binaryContentTypes - The list of content types that will be treated as binary\n *\n * @breadcrumb Core / isBinary\n * @public\n */\nexport function isContentTypeBinary(\n  headers: BothValueHeaders,\n  binaryContentTypes: string[],\n) {\n  const contentType = getContentType(headers);\n\n  if (!contentType) return false;\n\n  return binaryContentTypes.includes(contentType.trim());\n}\n\n/**\n * The function used to determine from the headers and the binary settings if a response should be encoded or not\n *\n * @example\n * ```typescript\n * const headers = { 'content-type': 'image/png', 'content-encoding': 'gzip' };\n * const isContentBinary = isBinary(headers, { contentEncodings: ['gzip'], contentTypes: ['image/png'] });\n * console.log(isContentBinary);\n * // true\n * ```\n *\n * @param headers - The headers of the response\n * @param binarySettings - The settings for the validation\n *\n * @breadcrumb Core / isBinary\n * @public\n */\nexport function isBinary(\n  headers: BothValueHeaders,\n  binarySettings: BinarySettings,\n): boolean {\n  if ('isBinary' in binarySettings) {\n    if (binarySettings.isBinary === false) return false;\n\n    return binarySettings.isBinary(headers);\n  }\n\n  return (\n    isContentEncodingBinary(headers, binarySettings.contentEncodings) ||\n    isContentTypeBinary(headers, binarySettings.contentTypes)\n  );\n}\n"
  },
  {
    "path": "src/core/logger.ts",
    "content": "import { NO_OP } from './no-op';\n\n/**\n * The type representing the possible log levels to choose from.\n *\n * @breadcrumb Core / Logger\n * @public\n */\nexport type LogLevels =\n  | 'debug'\n  | 'verbose'\n  | 'info'\n  | 'warn'\n  | 'error'\n  | 'none';\n\n/**\n * The options to customize {@link ILogger}\n *\n * @breadcrumb Core / Logger\n * @public\n */\nexport type LoggerOptions = {\n  /**\n   * Select the log level, {@link LogLevels | see more}.\n   *\n   * @defaultValue error\n   */\n  level: LogLevels;\n};\n\n/**\n * The log function used in any level.\n *\n * @breadcrumb Core / Logger\n * @public\n */\nexport type LoggerFN = (message: any, ...additional: any[]) => void;\n\n/**\n * The interface representing the logger, you can provide a custom logger by implementing this interface.\n *\n * @breadcrumb Core / Logger\n * @public\n */\nexport type ILogger = Record<Exclude<LogLevels, 'none'>, LoggerFN>;\n\n/**\n * The symbol used to check against an ILogger instace to verify if that ILogger was created by this library\n *\n * @breadcrumb Core / Logger\n * @public\n */\nconst InternalLoggerSymbol = Symbol('InternalLogger');\n\nconst logLevels: Record<\n  LogLevels,\n  [level: LogLevels, consoleMethod: keyof Console][]\n> = {\n  debug: [\n    ['debug', 'debug'],\n    ['verbose', 'debug'],\n    ['info', 'info'],\n    ['error', 'error'],\n    ['warn', 'warn'],\n  ],\n  verbose: [\n    ['verbose', 'debug'],\n    ['info', 'info'],\n    ['error', 'error'],\n    ['warn', 'warn'],\n  ],\n  info: [\n    ['info', 'info'],\n    ['error', 'error'],\n    ['warn', 'warn'],\n  ],\n  warn: [\n    ['warn', 'warn'],\n    ['error', 'error'],\n  ],\n  error: [['error', 'error']],\n  none: [],\n};\n\nconst lazyPrint = (value: () => any | unknown) => {\n  if (typeof value === 'function') return value();\n\n  return value;\n};\n\nconst print =\n  (fn: string) =>\n  (message: any, ...additional: (() => any)[]) =>\n    console[fn](message, ...additional.map(lazyPrint));\n\n/**\n * The method used to create a simple logger instance to use in this library.\n *\n * @remarks Behind the scenes, this simple logger sends the message to the `console` methods.\n *\n * @example\n * ```typescript\n * const logger = createDefaultLogger();\n *\n * logger.error('An error happens.');\n * // An error happens.\n * ```\n *\n * @param level - Select the level of the log\n *\n * @breadcrumb Core / Logger\n * @public\n */\nexport function createDefaultLogger(\n  { level }: LoggerOptions = { level: 'error' },\n): ILogger {\n  const levels = logLevels[level];\n\n  if (!levels) throw new Error('Invalid log level');\n\n  const logger = {\n    [InternalLoggerSymbol]: true,\n    error: NO_OP,\n    debug: NO_OP,\n    info: NO_OP,\n    verbose: NO_OP,\n    warn: NO_OP,\n  } as ILogger;\n\n  for (const [level, consoleMethod] of levels)\n    logger[level] = print(consoleMethod);\n\n  return logger;\n}\n\n/**\n * The method used to chck if logger was created by this library, or it was defined by the user.\n *\n * @param logger - The instance of the logger to check\n *\n * @breadcrumb Core / Logger\n * @public\n */\nexport function isInternalLogger(logger: ILogger): boolean {\n  return !!logger[InternalLoggerSymbol];\n}\n"
  },
  {
    "path": "src/core/no-op.ts",
    "content": "/**\n * No operation function is used when we need to pass a function, but we don't want to specify any behavior.\n *\n * @breadcrumb Core\n * @public\n */\nexport const NO_OP: (...args: any[]) => any = () => void 0;\n"
  },
  {
    "path": "src/core/optional.ts",
    "content": "/**\n * Return the defaultValue whether the value is undefined, otherwise, return the value.\n *\n * @example\n * ```typescript\n * const value1 = getDefaultIfUndefined(undefined, true);\n * const value2 = getDefaultIfUndefined(false, true);\n *\n * console.log(value1);\n * // true\n * console.log(value2);\n * // false\n * ```\n *\n * @param value - The value to be checked\n * @param defaultValue - The default value when value is undefined\n *\n * @breadcrumb Core\n * @public\n */\nexport function getDefaultIfUndefined<T>(\n  value: T | undefined,\n  defaultValue: T,\n): T {\n  if (value === undefined) return defaultValue;\n\n  return value;\n}\n"
  },
  {
    "path": "src/core/path.ts",
    "content": "/**\n * Transform the path and a map of query params to a string with formatted query params\n *\n * @example\n * ```typescript\n * const path = '/pets/search';\n * const queryParams = { batata: undefined, petType: [ 'dog', 'fish' ] };\n * const result = getPathWithQueryStringParams(path, queryParams);\n * console.log(result);\n * // /pets/search?batata=&petType=dog&petType=fish\n * ```\n *\n * @param path - The path\n * @param queryParams - The query params\n *\n * @breadcrumb Core / Path\n * @public\n */\nexport function getPathWithQueryStringParams(\n  path: string,\n  queryParams:\n    | string\n    | Record<string, string | string[] | undefined>\n    | undefined\n    | null,\n): string {\n  if (String(queryParams || '').length === 0) return path;\n\n  if (typeof queryParams === 'string') return `${path}?${queryParams}`;\n\n  const queryParamsString = getQueryParamsStringFromRecord(queryParams);\n\n  if (!queryParamsString) return path;\n\n  return `${path}?${queryParamsString}`;\n}\n\n/**\n * Map query params to a string with formatted query params\n *\n * @example\n * ```typescript\n * const queryParams = { batata: undefined, petType: [ 'dog', 'fish' ] };\n * const result = getQueryParamsStringFromRecord(queryParams);\n * console.log(result);\n * // batata=&petType=dog&petType=fish\n * ```\n *\n * @param queryParamsRecord - The query params record\n *\n * @breadcrumb Core / Path\n * @public\n */\nexport function getQueryParamsStringFromRecord(\n  queryParamsRecord:\n    | Record<string, string | string[] | undefined>\n    | undefined\n    | null,\n): string {\n  const searchParams = new URLSearchParams();\n\n  const multiValueHeadersEntries: [string, string | string[] | undefined][] =\n    Object.entries(queryParamsRecord || {});\n\n  if (multiValueHeadersEntries.length === 0) return '';\n\n  for (const [key, value] of multiValueHeadersEntries) {\n    if (!Array.isArray(value)) {\n      searchParams.append(key, value || '');\n      continue;\n    }\n\n    for (const arrayValue of value) searchParams.append(key, arrayValue);\n  }\n\n  return searchParams.toString();\n}\n\n/**\n * Type of the function to strip base path\n *\n * @breadcrumb Core / Path\n * @public\n */\nexport type StripBasePathFn = (path: string) => string;\n\nconst NOOPBasePath: StripBasePathFn = (path: string) => path;\n\n/**\n * Get the strip base path function\n *\n * @param basePath - The base path\n *\n * @breadcrumb Core / Path\n * @public\n */\nexport function buildStripBasePath(\n  basePath: string | undefined,\n): StripBasePathFn {\n  if (!basePath) return NOOPBasePath;\n\n  const length = basePath.length;\n\n  return (path: string) => {\n    if (path.startsWith(basePath))\n      return path.slice(path.indexOf(basePath) + length, path.length) || '/';\n\n    return path;\n  };\n}\n"
  },
  {
    "path": "src/core/stream.ts",
    "content": "//#region Imports\n\nimport { Readable, Writable } from 'node:stream';\n\n//#endregion\n\n/**\n * Check if stream already ended\n *\n * @param stream - The stream\n *\n * @breadcrumb Core / Stream\n * @public\n */\nexport function isStreamEnded(stream: Readable | Writable): boolean {\n  if ('readableEnded' in stream && stream.readableEnded) return true;\n\n  if ('writableEnded' in stream && stream.writableEnded) return true;\n\n  return false;\n}\n\n/**\n * Wait asynchronous the stream to complete\n *\n * @param stream - The stream\n *\n * @breadcrumb Core / Stream\n * @public\n */\nexport function waitForStreamComplete<TStream extends Readable | Writable>(\n  stream: TStream,\n): Promise<TStream> {\n  if (isStreamEnded(stream)) return Promise.resolve(stream);\n\n  return new Promise<TStream>((resolve, reject) => {\n    // Reading the {@link https://github.com/nodejs/node/blob/v12.22.9/lib/events.js#L262 | emit source code},\n    // it's almost impossible to complete being called twice because the emit function runs synchronously and removes the other listeners,\n    // but I'll leave it at that because I didn't write that code, so I couldn't figure out what the author thought when he wrote this.\n    let isComplete = false;\n\n    function complete(err: any) {\n      /* istanbul ignore next */\n      if (isComplete) return;\n\n      isComplete = true;\n\n      stream.removeListener('error', complete);\n      stream.removeListener('end', complete);\n      stream.removeListener('finish', complete);\n\n      if (err) reject(err);\n      else resolve(stream);\n    }\n\n    stream.once('error', complete);\n    stream.once('end', complete);\n    stream.once('finish', complete);\n  });\n}\n"
  },
  {
    "path": "src/frameworks/apollo-server/apollo-server.framework.ts",
    "content": "//#region\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport { type ApolloServer, type BaseContext, HeaderMap } from '@apollo/server';\nimport type { FrameworkContract } from '../../contracts';\nimport { ServerlessRequest } from '../../network';\nimport { getDefaultIfUndefined } from '../../core';\n\n//#endregion\n\n/**\n * The default context of Apollo Server when you integrate and don't pass any context.\n *\n * @breadcrumb Frameworks / ApolloServerFramework\n * @public\n */\nexport interface DefaultServerlessApolloServerContext extends BaseContext {\n  /**\n   * The request reference\n   */\n  request: IncomingMessage;\n  /**\n   * The response reference\n   */\n  response: ServerResponse;\n}\n\n/**\n * The arguments used to create a Context inside {@link ApolloServerOptions}\n *\n * @breadcrumb Frameworks / ApolloServerFramework\n * @public\n */\nexport type ApolloServerContextArguments = {\n  /**\n   * The request reference\n   */\n  request: IncomingMessage;\n  /**\n   * The response reference\n   */\n  response: ServerResponse;\n};\n\n/**\n * The options to customize {@link ApolloServerFramework}\n *\n * @breadcrumb Frameworks / ApolloServerFramework\n * @public\n */\nexport interface ApolloServerOptions<TContext extends BaseContext> {\n  /**\n   * Define a function to create the context of Apollo Server\n   *\n   * @param options - Default options passed by library\n   */\n  context?: (options: ApolloServerContextArguments) => Promise<TContext>;\n}\n\n/**\n * The framework that forwards requests to Apollo Server\n *\n * @breadcrumb Frameworks / ApolloServerFramework\n * @public\n */\nexport class ApolloServerFramework<TContext extends BaseContext>\n  implements FrameworkContract<ApolloServer<TContext>>\n{\n  //#region Constructor\n\n  /**\n   * Construtor padrão\n   */\n  constructor(protected readonly options?: ApolloServerOptions<TContext>) {}\n\n  //#endregion\n\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest(\n    app: ApolloServer<TContext>,\n    request: ServerlessRequest,\n    response: ServerResponse,\n  ): void {\n    const headers = new HeaderMap();\n\n    for (const [key, value] of Object.entries(request.headers)) {\n      if (value === undefined) continue;\n\n      headers.set(\n        key,\n        Array.isArray(value) ? value.join(', ') : value.toString(),\n      );\n    }\n\n    const defaultContext: ApolloServerOptions<any>['context'] = context =>\n      Promise.resolve(context);\n\n    const context = () =>\n      getDefaultIfUndefined(\n        this.options?.context,\n        defaultContext,\n      )({ request, response });\n\n    const search = request.url?.startsWith('http')\n      ? (new URL(request.url).search ?? '')\n      : request.url?.split('?')[1] || '';\n\n    // we don't need to handle catch because of https://www.apollographql.com/docs/apollo-server/integrations/building-integrations/#handle-errors\n    app\n      .executeHTTPGraphQLRequest({\n        httpGraphQLRequest: {\n          method: request.method!.toUpperCase(),\n          headers,\n          body: request.body,\n          search,\n        },\n        context,\n      })\n      .then(async httpGraphQLResponse => {\n        // this section was copy and pasted from https://github.com/apollographql/apollo-server/blob/main/packages/server/src/express4/index.ts#L95\n\n        for (const [key, value] of httpGraphQLResponse.headers)\n          response.setHeader(key, value);\n\n        response.statusCode = httpGraphQLResponse.status || 200;\n\n        if (httpGraphQLResponse.body.kind === 'complete') {\n          response.end(httpGraphQLResponse.body.string);\n          return;\n        }\n\n        for await (const chunk of httpGraphQLResponse.body.asyncIterator) {\n          response.write(chunk);\n          // Express/Node doesn't define a way of saying \"it's time to send this\n          // data over the wire\"... but the popular `compression` middleware\n          // (which implements `accept-encoding: gzip` and friends) does, by\n          // monkey-patching a `flush` method onto the response. So we call it\n          // if it's there.\n          if (typeof (response as any).flush === 'function')\n            (response as any).flush();\n        }\n\n        response.end();\n      });\n  }\n}\n"
  },
  {
    "path": "src/frameworks/apollo-server/index.ts",
    "content": "export * from './apollo-server.framework';\n"
  },
  {
    "path": "src/frameworks/body-parser/base-body-parser.framework.ts",
    "content": "//#region Imports\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { NextHandleFunction } from 'connect';\nimport type { HttpError } from 'http-errors';\nimport type { FrameworkContract } from '../../contracts';\nimport { getDefaultIfUndefined } from '../../core';\n\n//#endregion\n\n/**\n * The options for {@link BaseBodyParserFramework}\n *\n * @breadcrumb Frameworks / BodyParserFramework\n * @public\n */\nexport type BodyParserOptions = {\n  /**\n   * Implements a custom way of handling error.\n   *\n   * @defaultValue {@link BaseBodyParserFramework.defaultHandleOnError}\n   *\n   * @example\n   * ```typescript\n   * customErrorHandler: (req: IncomingMessage, response: ServerResponse, error: HttpError<any>) => {\n   *   response.setHeader('content-type', 'text/plain');\n   *   response.statusCode = error.statusCode;\n   *   // always call end to return the error\n   *   response.end(error.message);\n   * }\n   * ```\n   *\n   * @param request - The referecene for request\n   * @param response - The reference for response\n   * @param error - The error throwed by body-parser\n   */\n  customErrorHandler?: (\n    request: IncomingMessage,\n    response: ServerResponse,\n    error: HttpError<any>,\n  ) => void;\n};\n\n/**\n * The base class used by other body-parser functions to parse a specific content-type\n *\n * @breadcrumb Frameworks / BodyParserFramework\n * @public\n */\nexport class BaseBodyParserFramework<TApp> implements FrameworkContract<TApp> {\n  //#region Constructor\n\n  /**\n   * Default Constructor\n   */\n  protected constructor(\n    protected readonly framework: FrameworkContract<TApp>,\n    protected readonly middleware: NextHandleFunction,\n    protected readonly options?: BodyParserOptions,\n  ) {\n    this.errorHandler = getDefaultIfUndefined(\n      this.options?.customErrorHandler,\n      this.defaultHandleOnError.bind(this),\n    );\n  }\n\n  //#endregion\n\n  //#region Protected Properties\n\n  /**\n   * The selected error handler\n   */\n  protected readonly errorHandler: NonNullable<\n    BodyParserOptions['customErrorHandler']\n  >;\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest(\n    app: TApp,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): void {\n    this.middleware(\n      request,\n      response,\n      this.onBodyParserFinished(app, request, response),\n    );\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Handle next execution called by the cors package\n   */\n  protected onBodyParserFinished(\n    app: TApp,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): () => void {\n    return (err?: any) => {\n      if (err) return this.errorHandler(request, response, err);\n\n      this.framework.sendRequest(app, request, response);\n    };\n  }\n\n  /**\n   * The default function to handle errors\n   *\n   * @param _request - The referecene for request\n   * @param response - The reference for response\n   * @param error - The error throwed by body-parser\n   */\n  protected defaultHandleOnError(\n    _request: IncomingMessage,\n    response: ServerResponse,\n    error: HttpError<any>,\n  ): void {\n    response.setHeader('content-type', 'text/plain');\n    response.statusCode = error.statusCode;\n    response.end(error.message);\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/frameworks/body-parser/index.ts",
    "content": "export * from './base-body-parser.framework';\nexport * from './json-body-parser.framework';\nexport * from './raw-body-parser.framework';\nexport * from './text-body-parser.framework';\nexport * from './urlencoded-body-parser.framework';\n"
  },
  {
    "path": "src/frameworks/body-parser/json-body-parser.framework.ts",
    "content": "//#region Imports\n\nimport { type OptionsJson, json } from 'body-parser';\nimport { type FrameworkContract } from '../../contracts';\nimport {\n  BaseBodyParserFramework,\n  type BodyParserOptions,\n} from './base-body-parser.framework';\n\n//#endregion\n\n/**\n * The body-parser options for application/json\n *\n * @remarks {@link https://github.com/expressjs/body-parser#bodyparserjsonoptions}\n *\n * @breadcrumb Frameworks / BodyParserFramework / JsonBodyParserFramework\n * @public\n */\nexport type JsonBodyParserFrameworkOptions = OptionsJson & BodyParserOptions;\n\n/**\n * The body-parser class used to parse application/json.\n *\n * @breadcrumb Frameworks / BodyParserFramework / JsonBodyParserFramework\n * @public\n */\nexport class JsonBodyParserFramework<TApp>\n  extends BaseBodyParserFramework<TApp>\n  implements FrameworkContract<TApp>\n{\n  //#region Constructor\n\n  /**\n   * Default Constructor\n   */\n  constructor(\n    framework: FrameworkContract<TApp>,\n    options?: JsonBodyParserFrameworkOptions,\n  ) {\n    super(framework, json(options), options);\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/frameworks/body-parser/raw-body-parser.framework.ts",
    "content": "//#region Imports\n\nimport { type Options, raw } from 'body-parser';\nimport type { FrameworkContract } from '../../contracts';\nimport {\n  BaseBodyParserFramework,\n  type BodyParserOptions,\n} from './base-body-parser.framework';\n\n//#endregion\n\n/**\n * The body-parser options for application/octet-stream\n *\n * @remarks {@link https://github.com/expressjs/body-parser#bodyparserrawoptions}\n *\n * @breadcrumb Frameworks / BodyParserFramework / RawBodyParserFramework\n * @public\n */\nexport type RawBodyParserFrameworkOptions = Options & BodyParserOptions;\n\n/**\n * The body-parser class used to parse application/octet-stream.\n *\n * @breadcrumb Frameworks / BodyParserFramework / RawBodyParserFramework\n * @public\n */\nexport class RawBodyParserFramework<TApp>\n  extends BaseBodyParserFramework<TApp>\n  implements FrameworkContract<TApp>\n{\n  //#region Constructor\n\n  /**\n   * Default Constructor\n   */\n  constructor(\n    framework: FrameworkContract<TApp>,\n    options?: RawBodyParserFrameworkOptions,\n  ) {\n    super(framework, raw(options), options);\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/frameworks/body-parser/text-body-parser.framework.ts",
    "content": "//#region Imports\n\nimport { type OptionsText, text } from 'body-parser';\nimport type { FrameworkContract } from '../../contracts';\nimport {\n  BaseBodyParserFramework,\n  type BodyParserOptions,\n} from './base-body-parser.framework';\n\n//#endregion\n\n/**\n * The body-parser options for text/plain\n *\n * @remarks {@link https://github.com/expressjs/body-parser#bodyparsertextoptions}\n *\n * @breadcrumb Frameworks / BodyParserFramework / TextBodyParserFramework\n * @public\n */\nexport type TextBodyParserFrameworkOptions = OptionsText & BodyParserOptions;\n\n/**\n * The body-parser class used to parse text/plain.\n *\n * @breadcrumb Frameworks / BodyParserFramework / TextBodyParserFramework\n * @public\n */\nexport class TextBodyParserFramework<TApp>\n  extends BaseBodyParserFramework<TApp>\n  implements FrameworkContract<TApp>\n{\n  //#region Constructor\n\n  /**\n   * Default Constructor\n   */\n  constructor(\n    framework: FrameworkContract<TApp>,\n    options?: TextBodyParserFrameworkOptions,\n  ) {\n    super(framework, text(options), options);\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/frameworks/body-parser/urlencoded-body-parser.framework.ts",
    "content": "//#region Imports\n\nimport { type OptionsUrlencoded, urlencoded } from 'body-parser';\nimport { type FrameworkContract } from '../../contracts';\nimport {\n  BaseBodyParserFramework,\n  type BodyParserOptions,\n} from './base-body-parser.framework';\n\n//#endregion\n\n/**\n * The body parser options for application/x-www-form-urlencoded\n *\n * @remarks {@link https://github.com/expressjs/body-parser#bodyparserurlencodedoptions}\n *\n * @breadcrumb Frameworks / BodyParserFramework / UrlencodedBodyParserFramework\n * @public\n */\nexport type UrlencodedBodyParserFrameworkOptions = OptionsUrlencoded &\n  BodyParserOptions;\n\n/**\n * The body-parser class used to parse application/x-www-form-urlencoded.\n *\n * @breadcrumb Frameworks / BodyParserFramework / UrlencodedBodyParserFramework\n * @public\n */\nexport class UrlencodedBodyParserFramework<TApp>\n  extends BaseBodyParserFramework<TApp>\n  implements FrameworkContract<TApp>\n{\n  //#region Constructor\n\n  /**\n   * Default Constructor\n   */\n  constructor(\n    framework: FrameworkContract<TApp>,\n    options?: UrlencodedBodyParserFrameworkOptions,\n  ) {\n    super(framework, urlencoded(options), options);\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/frameworks/cors/cors.framework.ts",
    "content": "//#region Imports\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport cors, { type CorsOptions } from 'cors';\nimport type { FrameworkContract } from '../../contracts';\nimport { getDefaultIfUndefined } from '../../core';\n\n//#endregion\n\n/**\n * The options to customize {@link CorsFramework}\n *\n * @breadcrumb Frameworks / CorsFramework\n * @public\n */\nexport type CorsFrameworkOptions = CorsOptions & {\n  /**\n   * Send error 403 when cors is invalid. From what I read in `cors`, `fastify/cors` and [this problem](https://stackoverflow.com/questions/57212248/why-is-http-request-been-processed-in-action-even-when-cors-is-not-enabled)\n   * it is normal to process the request even if the origin is invalid.\n   * So this option will respond with error if this method was called from an invalid origin (or not allowed method) like [access control lib](https://github.com/primus/access-control/blob/master/index.js#L95-L115) .\n   *\n   * @defaultValue true\n   */\n  forbiddenOnInvalidOriginOrMethod?: boolean;\n};\n\n/**\n * The framework that handles cors for your api without relying on internals of the framework\n *\n * @example\n * ```typescript\n * import express from 'express';\n * import { ServerlessAdapter } from '@h4ad/serverless-adapter';\n * import { ExpressFramework } from '@h4ad/serverless-adapter/lib/frameworks/express';\n * import { CorsFramework } from '@h4ad/serverless-adapter/lib/frameworks/cors';\n *\n * const expressFramework = new ExpressFramework();\n * const options: CorsOptions = {}; // customize the options\n * const framework = new CorsFramework(expressFramework, options);\n *\n * export const handler = ServerlessAdapter.new(null)\n *   .setFramework(framework)\n *   // set other configurations and then build\n *   .build();\n * ```\n *\n * @breadcrumb Frameworks / CorsFramework\n * @public\n */\nexport class CorsFramework<TApp> implements FrameworkContract<TApp> {\n  //#region Constructor\n\n  /**\n   * Default Constructor\n   */\n  constructor(\n    protected readonly framework: FrameworkContract<TApp>,\n    protected readonly options?: CorsFrameworkOptions,\n  ) {\n    this.cachedCorsInstance = cors(this.options);\n  }\n\n  //#endregion\n\n  /**\n   * All cors headers that can be added by cors package\n   */\n  protected readonly corsHeaders: string[] = [\n    'Access-Control-Max-Age',\n    'Access-Control-Expose-Headers',\n    'Access-Control-Allow-Headers',\n    'Access-Control-Request-Headers',\n    'Access-Control-Allow-Credentials',\n    'Access-Control-Allow-Methods',\n    'Access-Control-Allow-Origin',\n  ];\n\n  /**\n   * The cached instance of cors\n   */\n  protected readonly cachedCorsInstance: ReturnType<typeof cors>;\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest(\n    app: TApp,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): void {\n    this.cachedCorsInstance(\n      request,\n      response,\n      this.onCorsNext(app, request, response),\n    );\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Handle next execution called by the cors package\n   */\n  protected onCorsNext(\n    app: TApp,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): () => void {\n    return () => {\n      this.formatHeaderValuesAddedByCorsPackage(response);\n\n      const errorOnInvalidOrigin = getDefaultIfUndefined(\n        this.options?.forbiddenOnInvalidOriginOrMethod,\n        true,\n      );\n\n      if (errorOnInvalidOrigin) {\n        const allowedOrigin = response.getHeader('access-control-allow-origin');\n        const isInvalidOrigin = this.isInvalidOriginOrMethodIsNotAllowed(\n          request,\n          allowedOrigin,\n        );\n\n        if (isInvalidOrigin) {\n          response.statusCode = 403;\n          response.setHeader('Content-Type', 'text/plain');\n          response.end(\n            [\n              'Invalid HTTP Access Control (CORS) request:',\n              `  Origin: ${request.headers.origin}`,\n              `  Method: ${request.method}`,\n            ].join('\\n'),\n          );\n\n          return;\n        }\n      }\n\n      this.framework.sendRequest(app, request, response);\n    };\n  }\n\n  /**\n   * Format the headers to be standardized with the rest of the library, such as ApiGatewayV2.\n   * Also, some frameworks don't support headers as an array, so we need to format the values.\n   */\n  protected formatHeaderValuesAddedByCorsPackage(\n    response: ServerResponse,\n  ): void {\n    for (const corsHeader of this.corsHeaders) {\n      const value = response.getHeader(corsHeader);\n\n      if (value === undefined) continue;\n\n      response.removeHeader(corsHeader);\n      response.setHeader(\n        corsHeader.toLowerCase(),\n        Array.isArray(value) ? value.join(',') : value,\n      );\n    }\n  }\n\n  /**\n   * Check if the origin is invalid or if the method is not allowed.\n   * Highly inspired by [access-control](https://github.com/primus/access-control/blob/master/index.js#L95-L115)\n   */\n  protected isInvalidOriginOrMethodIsNotAllowed(\n    request: IncomingMessage,\n    allowedOrigin: number | string | string[] | undefined,\n  ): boolean {\n    if (!allowedOrigin) return true;\n\n    if (\n      !!request.headers.origin &&\n      allowedOrigin !== '*' &&\n      request.headers.origin !== allowedOrigin\n    )\n      return true;\n\n    const notPermitedInMethods =\n      this.options &&\n      Array.isArray(this.options.methods) &&\n      this.options.methods.every(\n        m => m.toLowerCase() !== request.method?.toLowerCase(),\n      );\n    const differentMethod =\n      this.options &&\n      typeof this.options.methods === 'string' &&\n      this.options.methods\n        .split(',')\n        .every(m => m.trim().toLowerCase() !== request.method?.toLowerCase());\n\n    if (this.options?.methods && (notPermitedInMethods || differentMethod))\n      return true;\n\n    return false;\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/frameworks/cors/index.ts",
    "content": "export * from './cors.framework';\n"
  },
  {
    "path": "src/frameworks/deepkit/http-deepkit.framework.ts",
    "content": "//#region\n\nimport type { ServerResponse } from 'http';\nimport { HttpKernel, HttpResponse, RequestBuilder } from '@deepkit/http';\nimport type { FrameworkContract } from '../../contracts';\nimport { getFlattenedHeadersMap } from '../../core';\nimport { ServerlessRequest } from '../../network';\n\n//#endregion\n\n/**\n * The framework that forwards requests to express handler\n *\n * @breadcrumb Frameworks / HttpDeepkitFramework\n * @public\n */\nexport class HttpDeepkitFramework implements FrameworkContract<HttpKernel> {\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest(\n    app: HttpKernel,\n    request: ServerlessRequest,\n    response: ServerResponse,\n  ): void {\n    const flattenedHeaders = getFlattenedHeadersMap(request.headers);\n\n    let requestBuilder = new RequestBuilder(\n      request.url!,\n      request.method,\n    ).headers(flattenedHeaders);\n\n    if (request.body) {\n      requestBuilder = Buffer.isBuffer(request.body)\n        ? requestBuilder.body(request.body)\n        : requestBuilder.body(Buffer.from(request.body));\n    }\n\n    const httpRequest = requestBuilder.build();\n\n    app.handleRequest(httpRequest, response as HttpResponse);\n  }\n}\n"
  },
  {
    "path": "src/frameworks/deepkit/index.ts",
    "content": "export * from './http-deepkit.framework';\n"
  },
  {
    "path": "src/frameworks/express/express.framework.ts",
    "content": "//#region\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { Express } from 'express';\nimport type { FrameworkContract } from '../../contracts';\n\n//#endregion\n\n/**\n * The framework that forwards requests to express handler\n *\n * @breadcrumb Frameworks / ExpressFramework\n * @public\n */\nexport class ExpressFramework implements FrameworkContract<Express> {\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest(\n    app: Express,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): void {\n    app(request, response);\n  }\n}\n"
  },
  {
    "path": "src/frameworks/express/index.ts",
    "content": "export * from './express.framework';\n"
  },
  {
    "path": "src/frameworks/fastify/fastify.framework.ts",
    "content": "//#region Imports\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { FastifyInstance } from 'fastify';\nimport type { FrameworkContract } from '../../contracts';\n\n//#endregion\n\n/**\n * The framework that forwards requests to fastify handler\n *\n * @breadcrumb Frameworks / FastifyFramework\n * @public\n */\nexport class FastifyFramework implements FrameworkContract<FastifyInstance> {\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest(\n    app: FastifyInstance,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): void {\n    // ref: https://www.fastify.io/docs/latest/Guides/Serverless/#implement-and-export-the-function\n    app.ready().then(() => app.server.emit('request', request, response));\n  }\n}\n"
  },
  {
    "path": "src/frameworks/fastify/helpers/no-op-content-parser.ts",
    "content": "//#region Imports\n\nimport type { FastifyInstance } from 'fastify';\n\n//#endregion\n\n/**\n * Just return the current body as it was parsed.\n *\n * @remarks This function is intended to be used with BodyParserFrameworks.\n *\n * @param app - The instance of fastify\n * @param contentType - The content type to be anuled\n *\n * @breadcrumb Frameworks / FastifyFramework / Helpers\n * @public\n */\nexport function setNoOpForContentType(\n  app: FastifyInstance,\n  contentType: string,\n): void {\n  app.addContentTypeParser(contentType, (_, req, done) => {\n    return done(null, (req as any).body);\n  });\n}\n"
  },
  {
    "path": "src/frameworks/fastify/index.ts",
    "content": "export * from './fastify.framework';\n"
  },
  {
    "path": "src/frameworks/hapi/hapi.framework.ts",
    "content": "//#region Imports\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { Server } from '@hapi/hapi';\nimport type { FrameworkContract } from '../../contracts';\n\n//#endregion\n\n/**\n * The framework that forwards requests to hapi handler\n *\n * @breadcrumb Frameworks / HapiFramework\n * @public\n */\nexport class HapiFramework implements FrameworkContract<Server> {\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest(\n    app: Server,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): void {\n    const httpServer: any = app.listener;\n\n    httpServer._events.request(request, response);\n  }\n}\n"
  },
  {
    "path": "src/frameworks/hapi/index.ts",
    "content": "export * from './hapi.framework';\n"
  },
  {
    "path": "src/frameworks/koa/index.ts",
    "content": "export * from './koa.framework';\n"
  },
  {
    "path": "src/frameworks/koa/koa.framework.ts",
    "content": "//#region Imports\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type Application from 'koa';\nimport type { FrameworkContract } from '../../contracts';\n\n//#endregion\n\n/**\n * The framework that forwards requests to koa handler\n *\n * @breadcrumb Frameworks / KoaFramework\n * @public\n */\nexport class KoaFramework implements FrameworkContract<Application> {\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest(\n    app: Application,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): void {\n    app.callback()(request, response);\n  }\n}\n"
  },
  {
    "path": "src/frameworks/lazy/index.ts",
    "content": "export * from './lazy.framework';\n"
  },
  {
    "path": "src/frameworks/lazy/lazy.framework.ts",
    "content": "//#region Imports\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { FrameworkContract } from '../../contracts';\nimport { type ILogger, createDefaultLogger } from '../../core';\n\n//#endregion\n\n/**\n * The framework that asynchronously instantiates your application and forwards the request to the framework as quickly as possible.\n *\n * @example\n * ```typescript\n * import express from 'express';\n * import { ServerlessAdapter } from '@h4ad/serverless-adapter';\n * import { ExpressFramework } from '@h4ad/serverless-adapter/lib/frameworks/express';\n * import { LazyFramework } from '@h4ad/serverless-adapter/lib/frameworks/lazy';\n *\n * const expressFramework = new ExpressFramework();\n * const factory = async () => {\n *   const app = express();\n *\n *   // do some asynchronous stuffs like create the database;\n *   await new Promise(resolve => setTimeout(resolve, 100);\n *\n *   return app;\n * };\n * const framework = new LazyFramework(expressFramework, factory);\n *\n * export const handler = ServerlessAdapter.new(null)\n *   .setFramework(framework)\n *   // set other configurations and then build\n *   .build();\n * ```\n *\n * @breadcrumb Frameworks / LazyFramework\n * @public\n */\nexport class LazyFramework<TApp> implements FrameworkContract<null> {\n  //#region Constructor\n\n  /**\n   * Default Constructor\n   */\n  constructor(\n    protected readonly framework: FrameworkContract<TApp>,\n    protected readonly factory: () => Promise<TApp>,\n    protected readonly logger: ILogger = createDefaultLogger(),\n  ) {\n    this.delayedFactory = Promise.resolve()\n      .then(() => factory())\n      .then(app => {\n        this.cachedApp = app;\n      })\n      .catch((error: Error) => {\n        // deal with the error only when receive some request\n        // to be able to return some message to user\n        this.logger.error(\n          'SERVERLESS_ADAPTER:LAZY_FRAMEWORK: An error occours during the creation of your app.',\n        );\n        this.logger.error(error);\n      });\n  }\n\n  //#endregion\n\n  //#region Protected Properties\n\n  /**\n   * The cached version of the app\n   */\n  protected cachedApp?: TApp;\n\n  /**\n   * The delayed factory to create an instance of the app\n   */\n  protected readonly delayedFactory: Promise<void>;\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest(\n    _app: null,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): void {\n    if (this.cachedApp)\n      return this.framework.sendRequest(this.cachedApp, request, response);\n\n    this.delayedFactory.then(() => {\n      if (!this.cachedApp) {\n        return response.emit(\n          'error',\n          new Error(\n            'SERVERLESS_ADAPTER:LAZY_FRAMEWORK: The instance of the app returned by the factory is not valid, see the logs to learn more.',\n          ),\n        );\n      }\n\n      return this.framework.sendRequest(this.cachedApp, request, response);\n    });\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/frameworks/polka/index.ts",
    "content": "export * from './polka.framework';\n"
  },
  {
    "path": "src/frameworks/polka/polka.framework.ts",
    "content": "//#region Imports\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport polka, { type Polka } from 'polka';\nimport type { FrameworkContract } from '../../contracts';\n\n//#endregion\n\n/**\n * The framework that forwards requests to polka handler\n *\n * @breadcrumb Frameworks / PolkaFramework\n * @public\n */\nexport class PolkaFramework implements FrameworkContract<Polka> {\n  /**\n   * {@inheritDoc}\n   */\n  sendRequest(\n    app: Polka,\n    request: IncomingMessage,\n    response: ServerResponse<IncomingMessage>,\n  ): void {\n    app.handler(request as polka.Request, response);\n  }\n}\n"
  },
  {
    "path": "src/frameworks/trpc/index.ts",
    "content": "export * from './trpc.framework';\n"
  },
  {
    "path": "src/frameworks/trpc/trpc.framework.ts",
    "content": "//#region\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { AnyRouter, DataTransformer } from '@trpc/server';\nimport {\n  type NodeHTTPCreateContextFn,\n  type NodeHTTPCreateContextFnOptions,\n  type NodeHTTPHandlerOptions,\n  nodeHTTPRequestHandler,\n} from '@trpc/server/adapters/node-http';\nimport type { SingleValueHeaders } from '../../@types';\nimport type { FrameworkContract } from '../../contracts';\nimport { getDefaultIfUndefined, getFlattenedHeadersMap } from '../../core';\n\n//#endregion\n\n/**\n * The transformer that is responsible to transform buffer's input to javascript objects\n *\n * @deprecated You should use {@link JsonBodyParserFramework} instead, is more reliable and enable you to use transformer of trpc to other things.\n * @breadcrumb Frameworks / TrpcFramework\n * @public\n */\nexport class BufferToJSObjectTransformer implements DataTransformer {\n  /**\n   * Deserialize unknown values to javascript objects\n   *\n   * @param value - The value to be deserialized\n   */\n  public deserialize(value?: unknown): any {\n    if (value instanceof Buffer) return JSON.parse(value.toString('utf-8'));\n\n    return value;\n  }\n\n  /**\n   * The value to be serialized, do nothing because tRPC can handle.\n   *\n   * @param value - The value to be serialized\n   */\n  public serialize(value: any): any {\n    return value;\n  }\n}\n\n/**\n * The context created by this library that allows getting some information from the request and setting the status and header of the response.\n *\n * @breadcrumb Frameworks / TrpcFramework\n * @public\n */\nexport interface TrpcAdapterBaseContext {\n  /**\n   * The request object that will be forward to your app\n   */\n  request: IncomingMessage;\n\n  /**\n   * The response object that will be forward to your app to output the response\n   */\n  response: ServerResponse;\n\n  /**\n   * The method to set response status.\n   *\n   * @param statusCode - The response status that you want\n   */\n  setStatus(statusCode: number): void;\n\n  /**\n   * The method to set some header in the response\n   *\n   * @param name - The name of the header\n   * @param value - The value to be set in the header\n   */\n  setHeader(name: string, value: number | string): void;\n\n  /**\n   * The method to remove some header from the response\n   *\n   * @param name - The name of the header\n   */\n  removeHeader(name: string): void;\n\n  /**\n   * The method to return the value of some header from the request\n   *\n   * @param name - The name of the header\n   */\n  getHeader(name: string): string | undefined;\n\n  /**\n   * The method to return the request headers\n   */\n  getHeaders(): SingleValueHeaders;\n\n  /**\n   * The method to return user's address\n   */\n  getIp(): string | undefined;\n\n  /**\n   * The method to return the URL called\n   */\n  getUrl(): string | undefined;\n\n  /**\n   * The method to return the HTTP Method in the request\n   */\n  getMethod(): string | undefined;\n}\n\n/**\n * This is the context merged between {@link TrpcAdapterBaseContext} and the {@link TContext} that you provided.\n *\n * This context will be merged with the context you created with `createContext` inside {@link TrpcFrameworkOptions}.\n * So to make the type work, just send the properties you've added inside {@link TContext}.\n *\n * @example\n * ```typescript\n * type MyCustomContext = { user: { name: string } };\n * type TrpcContext = TrpcAdapterContext<MyCustomContext>; // your final context type to put inside trpc.router\n * ```\n *\n * @breadcrumb Frameworks / TrpcFramework\n * @public\n */\nexport type TrpcAdapterContext<TContext> = TContext & TrpcAdapterBaseContext;\n\n/**\n * The options to customize the {@link TrpcFramework}\n *\n * @breadcrumb Frameworks / TrpcFramework\n * @public\n */\nexport type TrpcFrameworkOptions<TContext> = Omit<\n  NodeHTTPHandlerOptions<AnyRouter, IncomingMessage, ServerResponse>,\n  'router' | 'createContext'\n> & {\n  createContext?: (\n    opts: NodeHTTPCreateContextFnOptions<IncomingMessage, ServerResponse>,\n  ) =>\n    | Omit<TContext, keyof TrpcAdapterBaseContext>\n    | Promise<Omit<TContext, keyof TrpcAdapterBaseContext>>;\n};\n\n/**\n * The framework that forwards requests to TRPC handler\n *\n * @breadcrumb Frameworks / TrpcFramework\n * @public\n */\nexport class TrpcFramework<\n  TContext extends TrpcAdapterBaseContext,\n  TRouter extends AnyRouter = AnyRouter,\n> implements FrameworkContract<TRouter>\n{\n  //#region Constructor\n\n  /**\n   * Default constructor\n   */\n  constructor(protected readonly options?: TrpcFrameworkOptions<TContext>) {}\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest<TRouter extends AnyRouter>(\n    app: TRouter,\n    request: IncomingMessage,\n    response: ServerResponse,\n  ): void {\n    const endpoint = this.getSafeUrlForTrpc(request);\n\n    nodeHTTPRequestHandler({\n      req: request,\n      res: response,\n      path: endpoint,\n      router: app,\n      ...this.options,\n      createContext: createContextOptions =>\n        this.mergeDefaultContextWithOptionsContext(createContextOptions),\n    });\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Get safe url that can be used inside Trpc.\n   *\n   * @example\n   * ```typescript\n   * const url = getSafeUrlForTrpc('/users?input=hello');\n   * console.log(url); // users\n   * ```\n   *\n   * @param request - The request object that will be forward to your app\n   */\n  protected getSafeUrlForTrpc(request: IncomingMessage): string {\n    let url = request.url!;\n\n    if (url.startsWith('/')) url = url.slice(1);\n\n    if (url.includes('?')) url = url.split('?')[0];\n\n    return url;\n  }\n\n  /**\n   * Merge the default context ({@link TrpcAdapterContext}) with the context created by the user.\n   *\n   * @param createContextOptions - The options sent by trpc to create the context\n   */\n  protected mergeDefaultContextWithOptionsContext(\n    createContextOptions: NodeHTTPCreateContextFnOptions<\n      IncomingMessage,\n      ServerResponse\n    >,\n  ): TContext | Promise<TContext> {\n    const createContextFromOptions: NodeHTTPCreateContextFn<\n      AnyRouter,\n      IncomingMessage,\n      ServerResponse\n    > = getDefaultIfUndefined(\n      this.options?.createContext,\n      () =>\n        undefined as unknown as Omit<TContext, keyof TrpcAdapterBaseContext>,\n    );\n\n    const resolvedContext = createContextFromOptions(createContextOptions);\n\n    if (resolvedContext && resolvedContext.then) {\n      return resolvedContext.then(context =>\n        this.wrapResolvedContextWithDefaultContext(\n          context,\n          createContextOptions,\n        ),\n      );\n    }\n\n    return this.wrapResolvedContextWithDefaultContext(\n      resolvedContext,\n      createContextOptions,\n    );\n  }\n\n  /**\n   * Wraps the resolved context from the {@link TrpcFrameworkOptions} created with `createContext` and merge\n   * with the {@link TrpcAdapterContext} generated by the library.\n   *\n   * @param resolvedContext - The context created with `createContext` inside {@link TrpcFrameworkOptions}\n   * @param createContextOptions - The options sent by trpc to create the context\n   */\n  protected wrapResolvedContextWithDefaultContext(\n    resolvedContext: TContext,\n    createContextOptions: NodeHTTPCreateContextFnOptions<\n      IncomingMessage,\n      ServerResponse\n    >,\n  ): TContext {\n    const request = createContextOptions.req;\n    const response = createContextOptions.res;\n\n    return {\n      ...resolvedContext,\n      request,\n      response,\n      getUrl: () => request.url,\n      getMethod: () => request.method,\n      getHeaders: () => getFlattenedHeadersMap(request.headers, ',', true),\n      setHeader: (header, value) => {\n        response.setHeader(header, value);\n      },\n      removeHeader: header => {\n        response.removeHeader(header);\n      },\n      getHeader: (header: string) => {\n        return getFlattenedHeadersMap(request.headers, ',', true)[\n          header.toLowerCase()\n        ];\n      },\n      setStatus: (statusCode: number) => {\n        response.statusCode = statusCode;\n        // force undefined to get default message for the status code\n        // ref: https://nodejs.org/dist/latest-v16.x/docs/api/http.html#responsestatusmessage\n        response.statusMessage = undefined as any;\n      },\n      getIp: () => request.connection.remoteAddress,\n    };\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/handlers/aws/aws-stream.handler.ts",
    "content": "//#region Imports\n\nimport { Writable } from 'node:stream';\nimport { inspect } from 'node:util';\nimport type { APIGatewayProxyEventV2, Context } from 'aws-lambda';\nimport type { APIGatewayProxyStructuredResultV2 } from 'aws-lambda/trigger/api-gateway-proxy';\nimport type { BinarySettings } from '../../@types';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  FrameworkContract,\n  ResolverContract,\n  ServerlessHandler,\n} from '../../contracts';\nimport {\n  BaseHandler,\n  type ILogger,\n  getFlattenedHeadersMap,\n  setCurrentInvoke,\n  waitForStreamComplete,\n} from '../../core';\nimport { ServerlessRequest, ServerlessStreamResponse } from '../../network';\n\n//#endregion\n\n/**\n * @breadcrumb Handlers / AwsStreamHandler\n * @public\n */\nexport type AWSResponseStream = Writable;\n\n/**\n * @breadcrumb Handlers / AwsStreamHandler\n * @public\n */\nexport type AWSStreamResponseMetadata = Pick<\n  APIGatewayProxyStructuredResultV2,\n  'statusCode' | 'headers' | 'cookies'\n>;\n\n/**\n * @breadcrumb Handlers / AwsStreamHandler\n * @public\n */\ndeclare const awslambda: {\n  streamifyResponse: (\n    handler: (\n      event: APIGatewayProxyEventV2,\n      response: AWSResponseStream,\n      context: Context,\n    ) => Promise<void>,\n  ) => any;\n  HttpResponseStream: {\n    from: (\n      stream: AWSResponseStream,\n      httpResponseMetadata: AWSStreamResponseMetadata,\n    ) => AWSResponseStream;\n  };\n};\n\n/**\n * The interface that customizes the {@link AwsStreamHandler}\n *\n * @breadcrumb Handlers / AwsStreamHandler\n * @public\n */\nexport type AwsStreamHandlerOptions = {\n  /**\n   * Set the value of the property `callbackWaitsForEmptyEventLoop`, you can set to `false` to fix issues with long execution due to not cleaning the event loop ([ref](https://github.com/H4ad/serverless-adapter/issues/264)).\n   * In the next release, this value will be changed to `false`.\n   *\n   * @defaultValue undefined\n   */\n  callbackWaitsForEmptyEventLoop?: boolean;\n};\n\n/**\n * The interface that describes the internal context used by the {@link AwsStreamHandler}\n *\n * @breadcrumb Handlers / AwsStreamHandler\n * @public\n */\nexport type AWSStreamContext = {\n  /**\n   * The response stream provided by the serverless\n   */\n  response: AWSResponseStream;\n  /**\n   * The context provided by the serverless\n   */\n  context: Context;\n};\n\n/**\n * The class that implements a default serverless handler consisting of a function with event, context and callback parameters respectively\n *\n * @breadcrumb Handlers / AwsStreamHandler\n * @public\n */\nexport class AwsStreamHandler<TApp> extends BaseHandler<\n  TApp,\n  APIGatewayProxyEventV2,\n  AWSStreamContext,\n  void,\n  AWSStreamResponseMetadata,\n  void\n> {\n  //#region Constructor\n\n  /**\n   * Construtor padrão\n   */\n  constructor(private readonly options?: AwsStreamHandlerOptions) {\n    super();\n  }\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getHandler(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n    adapters: AdapterContract<\n      APIGatewayProxyEventV2,\n      AWSStreamContext,\n      AWSStreamResponseMetadata\n    >[],\n    _resolverFactory: ResolverContract<\n      unknown,\n      unknown,\n      unknown,\n      unknown,\n      unknown\n    >,\n    binarySettings: BinarySettings,\n    respondWithErrors: boolean,\n    log: ILogger,\n  ): ServerlessHandler<Promise<void>> {\n    return awslambda.streamifyResponse(async (event, response, context) => {\n      if (this.options?.callbackWaitsForEmptyEventLoop !== undefined) {\n        // TODO(h4ad): Set the following property to false by default\n        context.callbackWaitsForEmptyEventLoop =\n          this.options.callbackWaitsForEmptyEventLoop;\n      }\n\n      const streamContext = { response, context };\n\n      this.onReceiveRequest(\n        log,\n        event,\n        streamContext,\n        binarySettings,\n        respondWithErrors,\n      );\n\n      const adapter = this.getAdapterByEventAndContext(\n        event,\n        streamContext,\n        adapters,\n        log,\n      );\n\n      this.onResolveAdapter(log, adapter);\n\n      setCurrentInvoke({ event, context });\n\n      await this.forwardRequestToFramework(\n        app,\n        framework,\n        event,\n        streamContext,\n        adapter,\n        binarySettings,\n        log,\n      );\n    });\n  }\n\n  //#endregion\n\n  //#region Hooks\n\n  /**\n   * The hook executed on receive a request, before the request is being processed\n   *\n   * @param log - The instance of logger\n   * @param event - The event sent by serverless\n   * @param context - The context sent by serverless\n   * @param binarySettings - The binary settings\n   * @param respondWithErrors - Indicates whether the error stack should be included in the response or not\n   */\n  protected onReceiveRequest(\n    log: ILogger,\n    event: APIGatewayProxyEventV2,\n    context: AWSStreamContext,\n    binarySettings: BinarySettings,\n    respondWithErrors: boolean,\n  ): void {\n    log.debug('SERVERLESS_ADAPTER:PROXY', () => ({\n      event,\n      context: inspect(context, { depth: null }),\n      binarySettings,\n      respondWithErrors,\n    }));\n  }\n\n  /**\n   * The hook executed after resolve the adapter that will be used to handle the request and response\n   *\n   * @param log - The instance of logger\n   * @param adapter - The adapter resolved\n   */\n  protected onResolveAdapter(\n    log: ILogger,\n    adapter: AdapterContract<\n      APIGatewayProxyEventV2,\n      AWSStreamContext,\n      AWSStreamResponseMetadata\n    >,\n  ): void {\n    log.debug(\n      'SERVERLESS_ADAPTER:RESOLVED_ADAPTER_NAME: ',\n      adapter.getAdapterName(),\n    );\n  }\n\n  /**\n   * The hook executed after resolves the request values that will be sent to the framework\n   *\n   * @param log - The instance of logger\n   * @param requestValues - The request values returned by the adapter\n   */\n  protected onResolveRequestValues(\n    log: ILogger,\n    requestValues: AdapterRequest,\n  ): void {\n    log.debug(\n      'SERVERLESS_ADAPTER:FORWARD_REQUEST_TO_FRAMEWORK:REQUEST_VALUES',\n      () => ({\n        requestValues: {\n          ...requestValues,\n          body: requestValues.body?.toString(),\n        },\n      }),\n    );\n  }\n\n  /**\n   * The hook executed before sending response to the serverless with response from adapter\n   *\n   * @param log - The instance of logger\n   * @param successResponse - The success response resolved by the adapter\n   */\n  protected onForwardResponseAdapterResponse(\n    log: ILogger,\n    successResponse: AWSStreamResponseMetadata,\n  ) {\n    log.debug('SERVERLESS_ADAPTER:FORWARD_RESPONSE:EVENT_SOURCE_RESPONSE', {\n      successResponse,\n    });\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * The function to forward the event to the framework\n   *\n   * @param app - The instance of the app (express, hapi, etc...)\n   * @param framework - The framework that will process requests\n   * @param event - The event sent by serverless\n   * @param context - The context sent by serverless\n   * @param adapter - The adapter resolved to this event\n   * @param _binarySettings - The binary settings\n   * @param log - The instance of logger\n   */\n  protected async forwardRequestToFramework(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n    event: APIGatewayProxyEventV2,\n    context: AWSStreamContext,\n    adapter: AdapterContract<\n      APIGatewayProxyEventV2,\n      AWSStreamContext,\n      AWSStreamResponseMetadata\n    >,\n    _binarySettings: BinarySettings,\n    log: ILogger,\n  ): Promise<void> {\n    const requestValues = adapter.getRequest(event, context, log);\n\n    this.onResolveRequestValues(log, requestValues);\n\n    const request = new ServerlessRequest({\n      method: requestValues.method,\n      headers: requestValues.headers,\n      body: requestValues.body,\n      remoteAddress: requestValues.remoteAddress,\n      url: requestValues.path,\n    });\n\n    const response = new ServerlessStreamResponse({\n      method: requestValues.method,\n      onReceiveHeaders: (status, headers) => {\n        const flattenedHeaders = getFlattenedHeadersMap(headers);\n        const awsMetadata: AWSStreamResponseMetadata = {\n          statusCode: status,\n          headers: flattenedHeaders,\n        };\n\n        const cookies = headers['set-cookie'];\n\n        if (cookies) {\n          awsMetadata.cookies = Array.isArray(cookies) ? cookies : [cookies];\n\n          delete headers['set-cookie'];\n          delete flattenedHeaders['set-cookie'];\n        }\n\n        this.onForwardResponseAdapterResponse(log, awsMetadata);\n\n        const finalResponse = awslambda.HttpResponseStream.from(\n          context.response,\n          awsMetadata,\n        );\n\n        // We must call write with an empty string to trigger the awsMetadata to be sent\n        // https://github.com/aws/aws-lambda-nodejs-runtime-interface-client/blob/2ce88619fd176a5823bc5f38c5484d1cbdf95717/src/HttpResponseStream.js#L22\n        finalResponse.write('');\n\n        return finalResponse;\n      },\n      log,\n    });\n\n    framework.sendRequest(app, request, response);\n\n    log.debug(\n      'SERVERLESS_ADAPTER:FORWARD_REQUEST_TO_FRAMEWORK:WAITING_STREAM_COMPLETE',\n    );\n    await waitForStreamComplete(response);\n\n    log.debug(\n      'SERVERLESS_ADAPTER:FORWARD_REQUEST_TO_FRAMEWORK:STREAM_COMPLETE',\n    );\n    context.response.end();\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/handlers/aws/index.ts",
    "content": "export * from './aws-stream.handler';\n"
  },
  {
    "path": "src/handlers/azure/azure.handler.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n//#region Imports\n\nimport type { Context } from '@azure/functions';\nimport type { BinarySettings } from '../../@types';\nimport type {\n  AdapterContract,\n  FrameworkContract,\n  ResolverContract,\n  ServerlessHandler,\n} from '../../contracts';\nimport {\n  type ILogger,\n  getDefaultIfUndefined,\n  isInternalLogger,\n} from '../../core';\nimport { DefaultHandler } from '../default';\n\n//#endregion\n\n/**\n * The options to customize {@link AzureHandler}\n *\n * @breadcrumb Handlers / AzureHandler\n * @public\n */\nexport interface AzureHandlerOptions {\n  /**\n   * Indicates to use the context log instead console.log when logger is internal (created by the library)\n   *\n   * @defaultValue true\n   */\n  useContextLogWhenInternalLogger: boolean;\n}\n\n/**\n * The class that implements a serverless handler for Azure Function.\n *\n * When you don't specify a custom logger, the {@link Context} logger is used instead.\n *\n * @breadcrumb Handlers / AzureHandler\n * @public\n */\nexport class AzureHandler<\n  TApp,\n  TEvent,\n  TCallback,\n  TResponse,\n  TReturn,\n> extends DefaultHandler<TApp, TEvent, Context, TCallback, TResponse, TReturn> {\n  //#region Constructor\n\n  /**\n   * Default Constructor\n   */\n  constructor(protected readonly options?: AzureHandlerOptions) {\n    super();\n  }\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public override getHandler(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n    adapters: AdapterContract<TEvent, Context, TResponse>[],\n    resolverFactory: ResolverContract<\n      TEvent,\n      Context,\n      TCallback,\n      TResponse,\n      TReturn\n    >,\n    binarySettings: BinarySettings,\n    respondWithErrors: boolean,\n    log: ILogger,\n  ): ServerlessHandler<TReturn> {\n    return (context: Context, event: TEvent) => {\n      const useContextLogWhenInternalLogger = getDefaultIfUndefined(\n        this.options?.useContextLogWhenInternalLogger,\n        true,\n      );\n\n      if (isInternalLogger(log) && useContextLogWhenInternalLogger)\n        log = this.createLoggerFromContext(context);\n\n      const defaultHandler = super.getHandler(\n        app,\n        framework,\n        adapters,\n        resolverFactory,\n        binarySettings,\n        respondWithErrors,\n        log,\n      );\n\n      // remove this from context\n      // because user can mess it-up the things\n      // @ts-ignore\n      delete context.done;\n      delete context.res;\n\n      return defaultHandler(event, context, undefined);\n    };\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * Get the {@link ILogger} instance from logger of the context\n   *\n   * @param context - The Azure Context\n   */\n  protected createLoggerFromContext(context: Context): ILogger {\n    return {\n      error: context.log.error,\n      debug: context.log.verbose,\n      verbose: context.log.verbose,\n      info: context.log.info,\n      warn: context.log.warn,\n    };\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/handlers/azure/index.ts",
    "content": "export * from './azure.handler';\n"
  },
  {
    "path": "src/handlers/base/index.ts",
    "content": "export * from './raw-request';\n"
  },
  {
    "path": "src/handlers/base/raw-request.ts",
    "content": "//#region Imports\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { FrameworkContract } from '../../contracts';\nimport { ServerlessRequest } from '../../network';\nimport { getEventBodyAsBuffer, getFlattenedHeadersMap } from '../../core';\n\n//#endregion\n\n/**\n * The class that expose some methods to be used to get raw request from Express HTTP Request\n *\n * @breadcrumb Handlers / Base / RawRequest\n * @public\n */\nexport abstract class RawRequest<TApp> {\n  //#region Protected Methods\n\n  /**\n   * The callback to when receive some request from external source\n   *\n   * @param app - The instance of the app\n   * @param framework - The framework for the app\n   */\n  protected onRequestCallback(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n  ): (req: IncomingMessage, res: ServerResponse) => void | Promise<void> {\n    return (request: IncomingMessage, response: ServerResponse) => {\n      const customRequest = this.getRequestFromExpressRequest(request);\n\n      return framework.sendRequest(app, customRequest, response);\n    };\n  }\n\n  /**\n   * Not sure why they think using Express instance with prebuilt middlewares was a good idea, but Firebase/GCP\n   * decides to use `Express` and `body-parser` by default, so you don't get a raw request, instead, you get a modified version by\n   * Express and also with the body parsed by `body-parser`.\n   * If you use NestJS or Express it's awesome, but for the rest of the frameworks it's terrible!\n   * That's why I have this method, just to try and create a raw request to be used and passed to the frameworks so they can handle the request\n   * as if they received the request from the native http module.\n   *\n   * @param request - The Express request\n   */\n  protected getRequestFromExpressRequest(\n    request: IncomingMessage,\n  ): ServerlessRequest {\n    const expressRequestParsed = request as unknown as {\n      body: object | Buffer;\n    };\n\n    const headers = getFlattenedHeadersMap(request.headers, ',', true);\n    const remoteAddress = headers['x-forwarded-for'];\n\n    let body: Buffer | undefined;\n\n    if (\n      expressRequestParsed.body &&\n      typeof expressRequestParsed.body === 'object'\n    ) {\n      const jsonContent = JSON.stringify(expressRequestParsed.body);\n\n      const [bufferBody, contentLength] = getEventBodyAsBuffer(\n        jsonContent,\n        false,\n      );\n\n      body = bufferBody;\n      headers['content-length'] = String(contentLength);\n    }\n\n    return new ServerlessRequest({\n      method: request.method!,\n      url: request.url!,\n      body,\n      headers,\n      remoteAddress,\n    });\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/handlers/default/default.handler.ts",
    "content": "//#region Imports\n\nimport util from 'node:util';\nimport type { BinarySettings, SingleValueHeaders } from '../../@types';\nimport type {\n  AdapterContract,\n  AdapterRequest,\n  FrameworkContract,\n  ResolverContract,\n  ServerlessHandler,\n} from '../../contracts';\nimport {\n  BaseHandler,\n  type ILogger,\n  isBinary,\n  setCurrentInvoke,\n  waitForStreamComplete,\n} from '../../core';\nimport { ServerlessResponse } from '../../network';\n\n//#endregion\n\n/**\n * The class that implements a default serverless handler consisting of a function with event, context and callback parameters respectively\n *\n * @breadcrumb Handlers / DefaultHandler\n * @public\n */\nexport class DefaultHandler<\n  TApp,\n  TEvent,\n  TContext,\n  TCallback,\n  TResponse,\n  TReturn,\n> extends BaseHandler<TApp, TEvent, TContext, TCallback, TResponse, TReturn> {\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getHandler(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n    adapters: AdapterContract<TEvent, TContext, TResponse>[],\n    resolverFactory: ResolverContract<\n      TEvent,\n      TContext,\n      TCallback,\n      TResponse,\n      TReturn\n    >,\n    binarySettings: BinarySettings,\n    respondWithErrors: boolean,\n    log: ILogger,\n  ): ServerlessHandler<TReturn> {\n    return (event: TEvent, context: TContext, callback?: TCallback) => {\n      this.onReceiveRequest(\n        log,\n        event,\n        context,\n        binarySettings,\n        respondWithErrors,\n      );\n\n      const adapter = this.getAdapterByEventAndContext(\n        event,\n        context,\n        adapters,\n        log,\n      );\n\n      this.onResolveAdapter(log, adapter);\n\n      setCurrentInvoke({ event, context });\n\n      const resolver = resolverFactory.createResolver({\n        event,\n        context,\n        callback,\n        log,\n        respondWithErrors,\n        adapter,\n      });\n\n      return resolver.run(() =>\n        this.forwardRequestToFramework(\n          app,\n          framework,\n          event,\n          context,\n          adapter,\n          binarySettings,\n          log,\n        ),\n      );\n    };\n  }\n\n  //#endregion\n\n  //#region Hooks\n\n  /**\n   * The hook executed on receive a request, before the request is being processed\n   *\n   * @param log - The instance of logger\n   * @param event - The event sent by serverless\n   * @param context - The context sent by serverless\n   * @param binarySettings - The binary settings\n   * @param respondWithErrors - Indicates whether the error stack should be included in the response or not\n   */\n  protected onReceiveRequest(\n    log: ILogger,\n    event: TEvent,\n    context: TContext,\n    binarySettings: BinarySettings,\n    respondWithErrors: boolean,\n  ): void {\n    log.debug('SERVERLESS_ADAPTER:PROXY', () => ({\n      event: util.inspect(event, { depth: null }),\n      context: util.inspect(context, { depth: null }),\n      binarySettings,\n      respondWithErrors,\n    }));\n  }\n\n  /**\n   * The hook executed after resolve the adapter that will be used to handle the request and response\n   *\n   * @param log - The instance of logger\n   * @param adapter - The adapter resolved\n   */\n  protected onResolveAdapter(\n    log: ILogger,\n    adapter: AdapterContract<TEvent, TContext, TResponse>,\n  ): void {\n    log.debug(\n      'SERVERLESS_ADAPTER:RESOLVED_ADAPTER_NAME: ',\n      adapter.getAdapterName(),\n    );\n  }\n\n  /**\n   * The hook executed after resolves the request values that will be sent to the framework\n   *\n   * @param log - The instance of logger\n   * @param requestValues - The request values returned by the adapter\n   */\n  protected onResolveRequestValues(\n    log: ILogger,\n    requestValues: AdapterRequest,\n  ): void {\n    log.debug(\n      'SERVERLESS_ADAPTER:FORWARD_REQUEST_TO_FRAMEWORK:REQUEST_VALUES',\n      () => ({\n        requestValues: {\n          ...requestValues,\n          body: requestValues.body?.toString(),\n        },\n      }),\n    );\n  }\n\n  /**\n   * The hook executed after handling the response sent by the framework\n   *\n   * @param log - The instance of logger\n   * @param response - The response sent by the framework\n   */\n  protected onResolveForwardedResponseToFramework(\n    log: ILogger,\n    response: ServerlessResponse,\n  ): void {\n    log.debug(\n      'SERVERLESS_ADAPTER:FORWARD_REQUEST_TO_FRAMEWORK:RESPONSE',\n      () => ({\n        response,\n      }),\n    );\n  }\n\n  /**\n   * The hook executed before sending response to the serverless\n   *\n   * @param log - The instance of logger\n   * @param statusCode - The status code of the response\n   * @param body - The body of the response\n   * @param headers - The headers of the response\n   * @param isBase64Encoded - Indicates whether the response was encoded as binary or not\n   */\n  protected onForwardResponse(\n    log: ILogger,\n    statusCode: number,\n    body: string,\n    headers: SingleValueHeaders,\n    isBase64Encoded: boolean,\n  ) {\n    log.debug(\n      'SERVERLESS_ADAPTER:FORWARD_RESPONSE:EVENT_SOURCE_RESPONSE_PARAMS',\n      () => ({\n        statusCode,\n        body,\n        headers,\n        isBase64Encoded,\n      }),\n    );\n  }\n\n  /**\n   * The hook executed before sending response to the serverless with response from adapter\n   *\n   * @param log - The instance of logger\n   * @param successResponse - The success response resolved by the adapter\n   * @param body - The body of the response sent by the framework\n   */\n  protected onForwardResponseAdapterResponse(\n    log: ILogger,\n    successResponse: TResponse,\n    body: string,\n  ) {\n    log.debug(\n      'SERVERLESS_ADAPTER:FORWARD_RESPONSE:EVENT_SOURCE_RESPONSE',\n      () => ({\n        successResponse: util.inspect(successResponse, { depth: null }),\n        body,\n      }),\n    );\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * The function to forward the event to the framework\n   *\n   * @param app - The instance of the app (express, hapi, etc...)\n   * @param framework - The framework that will process requests\n   * @param event - The event sent by serverless\n   * @param context - The context sent by serverless\n   * @param adapter - The adapter resolved to this event\n   * @param log - The instance of logger\n   * @param binarySettings - The binary settings\n   */\n  protected async forwardRequestToFramework(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n    event: TEvent,\n    context: TContext,\n    adapter: AdapterContract<TEvent, TContext, TResponse>,\n    binarySettings: BinarySettings,\n    log: ILogger,\n  ): Promise<TResponse> {\n    const requestValues = adapter.getRequest(event, context, log);\n\n    this.onResolveRequestValues(log, requestValues);\n\n    const [request, response] =\n      this.getServerlessRequestResponseFromAdapterRequest(requestValues);\n\n    framework.sendRequest(app, request, response);\n\n    await waitForStreamComplete(response);\n\n    this.onResolveForwardedResponseToFramework(log, response);\n\n    return this.forwardResponse(event, response, adapter, binarySettings, log);\n  }\n\n  /**\n   * The function to forward the response back to the serverless\n   *\n   * @param event - The event sent by serverless\n   * @param response - The response of the framework\n   * @param adapter - The adapter resolved to this event\n   * @param binarySettings - The binary settings\n   * @param log - The instance of logger\n   */\n  protected forwardResponse(\n    event: TEvent,\n    response: ServerlessResponse,\n    adapter: AdapterContract<TEvent, TContext, TResponse>,\n    binarySettings: BinarySettings,\n    log: ILogger,\n  ): TResponse {\n    const statusCode = response.statusCode;\n    const headers = ServerlessResponse.headers(response);\n    const isBase64Encoded = isBinary(headers, binarySettings);\n    const encoding = isBase64Encoded ? 'base64' : 'utf8';\n    const body = ServerlessResponse.body(response).toString(encoding);\n    const logBody = isBase64Encoded ? '[BASE64_ENCODED]' : body;\n\n    this.onForwardResponse(log, statusCode, logBody, headers, isBase64Encoded);\n\n    const successResponse = adapter.getResponse({\n      event,\n      statusCode,\n      body,\n      headers,\n      isBase64Encoded,\n      response,\n      log,\n    });\n\n    this.onForwardResponseAdapterResponse(log, successResponse, logBody);\n\n    return successResponse;\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/handlers/default/index.ts",
    "content": "export * from './default.handler';\n"
  },
  {
    "path": "src/handlers/digital-ocean/digital-ocean.handler.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n//#region Imports\n\nimport type { BinarySettings } from '../../@types';\nimport type { DigitalOceanHttpEvent } from '../../@types/digital-ocean';\nimport type {\n  AdapterContract,\n  FrameworkContract,\n  ResolverContract,\n  ServerlessHandler,\n} from '../../contracts';\nimport type { ILogger } from '../../core';\nimport { DefaultHandler } from '../default';\n\n//#endregion\n\n/**\n * The class that implements a serverless handler for Digital Ocean Functions.\n *\n * @breadcrumb Handlers / DigitalOceanHandler\n * @public\n */\nexport class DigitalOceanHandler<\n  TApp,\n  TEvent,\n  TResponse,\n  TReturn,\n> extends DefaultHandler<TApp, TEvent, void, void, TResponse, TReturn> {\n  /**\n   * {@inheritDoc}\n   */\n  public override getHandler(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n    adapters: AdapterContract<TEvent, void, TResponse>[],\n    resolverFactory: ResolverContract<TEvent, void, void, TResponse, TReturn>,\n    binarySettings: BinarySettings,\n    respondWithErrors: boolean,\n    log: ILogger,\n  ): ServerlessHandler<TReturn> {\n    const defaultHandler = super.getHandler(\n      app,\n      framework,\n      adapters,\n      resolverFactory,\n      binarySettings,\n      respondWithErrors,\n      log,\n    );\n\n    return (event: DigitalOceanHttpEvent) =>\n      defaultHandler(event, undefined, undefined);\n  }\n}\n"
  },
  {
    "path": "src/handlers/digital-ocean/index.ts",
    "content": "export * from './digital-ocean.handler';\n"
  },
  {
    "path": "src/handlers/firebase/http-firebase-v2.handler.ts",
    "content": "//#region Imports\n\nimport { IncomingMessage, ServerResponse } from 'node:http';\n// eslint-disable-next-line import/no-unresolved\nimport { https } from 'firebase-functions/v2';\nimport type { FrameworkContract, HandlerContract } from '../../contracts';\nimport { RawRequest } from '../base';\n\n//#endregion\n\n/**\n * The HTTP handler that is exposed when you use {@link HttpFirebaseV2Handler}.\n *\n * @breadcrumb Handlers / HttpFirebaseHandler\n * @public\n */\nexport type FirebaseHttpHandler = (\n  request: IncomingMessage,\n  response: ServerResponse,\n) => void | Promise<void>;\n\n/**\n * The class that implements a handler for Firebase Https Events\n *\n * @remarks Read more about Https Events {@link https://firebase.google.com/docs/functions/http-events | here}\n *\n * @breadcrumb Handlers / HttpFirebaseHandler\n * @public\n */\nexport class HttpFirebaseV2Handler<TApp>\n  extends RawRequest<TApp>\n  implements\n    HandlerContract<TApp, never, never, never, void, void | Promise<void>>\n{\n  //#region Constructor\n\n  /**\n   * Construtor padrão\n   */\n  constructor(protected readonly options?: https.HttpsOptions) {\n    super();\n  }\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getHandler(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n  ): FirebaseHttpHandler {\n    if (this.options) {\n      return this.onRequestWithOptions(\n        this.options,\n        this.onRequestCallback(app, framework),\n      );\n    }\n\n    return https.onRequest(\n      this.onRequestCallback(app, framework),\n    ) as unknown as FirebaseHttpHandler;\n  }\n\n  //#endregion\n\n  //#region Protected Method\n\n  /**\n   * Wrapper method around onRequest for better testability\n   */\n  protected onRequestWithOptions(\n    options: https.HttpsOptions,\n    callback: ReturnType<HttpFirebaseV2Handler<TApp>['onRequestCallback']>,\n  ): FirebaseHttpHandler {\n    return https.onRequest(options, callback) as unknown as FirebaseHttpHandler;\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/handlers/firebase/http-firebase.handler.ts",
    "content": "//#region Imports\n\n// eslint-disable-next-line import/no-unresolved\nimport { type HttpsFunction, https } from 'firebase-functions/v1';\nimport type { FrameworkContract, HandlerContract } from '../../contracts';\nimport { RawRequest } from '../base';\n\n//#endregion\n/**\n * The class that implements a handler for Firebase Https Events\n *\n * @remarks Read more about Https Events {@link https://firebase.google.com/docs/functions/http-events | here}\n *\n * @breadcrumb Handlers / HttpFirebaseHandler\n * @public\n */\nexport class HttpFirebaseHandler<TApp>\n  extends RawRequest<TApp>\n  implements\n    HandlerContract<TApp, never, never, never, void, void | Promise<void>>\n{\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getHandler(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n  ): HttpsFunction {\n    return https.onRequest(this.onRequestCallback(app, framework));\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/handlers/firebase/index.ts",
    "content": "export * from './http-firebase.handler';\nexport * from './http-firebase-v2.handler';\n"
  },
  {
    "path": "src/handlers/gcp/gcp.handler.ts",
    "content": "//#region Imports\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport { http } from '@google-cloud/functions-framework';\nimport type { FrameworkContract, HandlerContract } from '../../contracts';\nimport { RawRequest } from '../base';\n\n//#endregion\n\n/**\n * The class that implements a handler for GCP Http Functions\n *\n * @remarks Read more about Http Cloud Function {@link https://cloud.google.com/functions/docs/create-deploy-http-nodejs | here}\n *\n * @breadcrumb Handlers / GCPHandler\n * @public\n */\nexport class GCPHandler<TApp>\n  extends RawRequest<TApp>\n  implements\n    HandlerContract<TApp, never, never, never, void, void | Promise<void>>\n{\n  //#region Constructor\n\n  /**\n   * Default Constructor\n   *\n   * @param name - The name of this function, should be the during deploy.\n   */\n  constructor(protected readonly name: string) {\n    super();\n  }\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getHandler(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n  ): (req: IncomingMessage, res: ServerResponse) => void | Promise<void> {\n    const callback = this.onRequestCallback(app, framework);\n\n    http(this.name, callback);\n\n    return callback;\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/handlers/gcp/index.ts",
    "content": "export * from './gcp.handler';\n"
  },
  {
    "path": "src/handlers/huawei/http-huawei.handler.ts",
    "content": "//#region Imports\n\nimport type { RequestListener } from 'http';\nimport { type Server, createServer } from 'node:http';\nimport type { BinarySettings } from '../../@types';\nimport type {\n  AdapterContract,\n  FrameworkContract,\n  HandlerContract,\n  ResolverContract,\n  ServerlessHandler,\n} from '../../contracts';\nimport { type ILogger, getDefaultIfUndefined } from '../../core';\n\n//#endregion\n\n/**\n * The default port that huawei will proxy the request to your framework\n *\n * {@link https://support.huaweicloud.com/intl/en-us/ae-ad-1-usermanual-functiongraph/functiongraph_01_1442.html#functiongraph_01_1442__li194597302096 | Reference}\n *\n * @breadcrumb Handlers / HttpHuaweiHandler\n * @public\n */\nexport const DEFAULT_HUAWEI_LISTEN_PORT: number = 8000;\n\n/**\n * The options to customize {@link HttpHuaweiHandler}\n *\n * @breadcrumb Handlers / HttpHuaweiHandler\n * @public\n */\nexport type HttpHuaweiHandlerOptions = {\n  /**\n   * @defaultValue {@link DEFAULT_HUAWEI_LISTEN_PORT}\n   */\n  port?: number;\n\n  /**\n   * The factory to create a http server to use to listen huawei requests\n   */\n  httpServerFactory?: (requestListener: RequestListener) => Server;\n};\n\n/**\n * The class that implements a huawei serverless handler with http function that exposes a http server in specific port.\n *\n * In this Handler, you don't need to specific resolver and adapter, so you can use DummyAdapter and DummyResolver instead.\n *\n * @see https://support.huaweicloud.com/intl/en-us/ae-ad-1-usermanual-functiongraph/functiongraph_01_1442.html#functiongraph_01_1442__li194597302096\n *\n * @breadcrumb Handlers / HttpHuaweiHandler\n * @public\n */\nexport class HttpHuaweiHandler<TApp>\n  implements HandlerContract<TApp, void, void, void, void, Promise<void>>\n{\n  //#region Constructor\n\n  /**\n   * Construtor padrão\n   */\n  constructor(protected readonly options?: HttpHuaweiHandlerOptions) {}\n\n  //#endregion\n\n  //#region Public Methods\n\n  /**\n   * {@inheritDoc}\n   */\n  public getHandler(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n    _adapters: AdapterContract<void, void, void>[],\n    _resolver: ResolverContract<void, void, void, void, void>,\n    _binarySettings: BinarySettings,\n    _respondWithErrors: boolean,\n    log: ILogger,\n  ): ServerlessHandler<Promise<void>> {\n    const requestListener: RequestListener = (req, res) => {\n      framework.sendRequest(app, req, res);\n    };\n\n    const server = getDefaultIfUndefined(\n      this.options?.httpServerFactory,\n      this.createHttpServer.bind(this),\n    )(requestListener);\n\n    const port = getDefaultIfUndefined(\n      this.options?.port,\n      DEFAULT_HUAWEI_LISTEN_PORT,\n    );\n\n    server.listen(port, () => {\n      log.debug('SERVERLESS_ADAPTER:PROXY: Server started.');\n      log.debug(\n        `SERVERLESS_ADAPTER:PROXY: Listening the Huawei Requests in port ${port}`,\n      );\n    });\n\n    return () => {\n      log.debug('SERVERLESS_ADAPTER:PROXY: Disposing the server');\n\n      return new Promise((resolve, reject) => {\n        server.close(err => (err ? reject(err) : resolve()));\n      });\n    };\n  }\n\n  //#endregion\n\n  //#region Protected Methods\n\n  /**\n   * The method that creates the instance of http server\n   *\n   * @param requestListener - O método que lidará com as requisições recebidas\n   */\n  protected createHttpServer(requestListener: RequestListener): Server {\n    return createServer(requestListener);\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "src/handlers/huawei/index.ts",
    "content": "export * from './http-huawei.handler';\n"
  },
  {
    "path": "src/index.doc.ts",
    "content": "export * from './@types';\nexport * from './@types/huawei';\nexport * from './adapters/apollo-server';\nexport * from './adapters/aws';\nexport * from './adapters/azure';\nexport * from './adapters/digital-ocean';\nexport * from './adapters/dummy';\nexport * from './adapters/huawei';\nexport * from './contracts';\nexport * from './core';\nexport * from './frameworks/apollo-server';\nexport * from './frameworks/body-parser';\nexport * from './frameworks/cors';\nexport * from './frameworks/deepkit';\nexport * from './frameworks/express';\nexport * from './frameworks/fastify';\nexport * from './frameworks/koa';\nexport * from './frameworks/hapi';\nexport * from './frameworks/lazy';\nexport * from './frameworks/polka';\nexport * from './frameworks/trpc';\nexport * from './handlers/azure';\nexport * from './handlers/aws';\nexport * from './handlers/base';\nexport * from './handlers/default';\nexport * from './handlers/digital-ocean';\nexport * from './handlers/firebase';\nexport * from './handlers/gcp';\nexport * from './handlers/huawei';\nexport * from './network';\nexport * from './resolvers/aws-context';\nexport * from './resolvers/callback';\nexport * from './resolvers/promise';\nexport * from './resolvers/dummy';\nexport * from './serverless-adapter';\n"
  },
  {
    "path": "src/index.ts",
    "content": "export * from './@types';\nexport * from './contracts';\nexport * from './core';\nexport * from './network';\nexport * from './serverless-adapter';\n"
  },
  {
    "path": "src/network/index.ts",
    "content": "export * from './request';\nexport * from './response';\nexport * from './response-stream';\nexport * from './utils';\n"
  },
  {
    "path": "src/network/request.ts",
    "content": "// ATTRIBUTION: https://github.com/dougmoscrop/serverless-http\nimport { IncomingMessage } from 'node:http';\nimport type { AddressInfo } from 'node:net';\nimport type { SingleValueHeaders } from '../@types';\nimport { NO_OP } from '../core';\n\nconst HTTPS_PORT = 443;\n\n/**\n * The properties to create a {@link ServerlessRequest}\n *\n * @breadcrumb Network / ServerlessRequest\n * @public\n */\nexport interface ServerlessRequestProps {\n  /**\n   * The HTTP Method of the request\n   */\n  method: string;\n\n  /**\n   * The URL requested\n   */\n  url: string;\n\n  /**\n   * The headers from the event source\n   */\n  headers: SingleValueHeaders;\n\n  /**\n   * The body from the event source\n   */\n  body?: Buffer | Uint8Array;\n\n  /**\n   * The IP Address from caller\n   */\n  remoteAddress?: string;\n}\n\n/**\n * The class that represents an {@link http#IncomingMessage} created by the library to represent an actual request to the framework.\n *\n * @breadcrumb Network / ServerlessRequest\n * @public\n */\nexport class ServerlessRequest extends IncomingMessage {\n  constructor({\n    method,\n    url,\n    headers,\n    body,\n    remoteAddress,\n  }: ServerlessRequestProps) {\n    super({\n      encrypted: true,\n      readable: true, // credits to @pnkp at https://github.com/CodeGenieApp/serverless-express/pull/692\n      remoteAddress,\n      address: () => ({ port: HTTPS_PORT }) as AddressInfo,\n      on: NO_OP,\n      removeListener: NO_OP,\n      removeEventListener: NO_OP,\n      end: NO_OP,\n      destroy: NO_OP,\n    } as any);\n\n    this.statusCode = 200;\n    this.statusMessage = 'OK';\n    this.complete = true;\n    this.httpVersion = '1.1';\n    this.httpVersionMajor = 1;\n    this.httpVersionMinor = 1;\n    this.method = method;\n    this.headers = headers;\n    this.body = body;\n    this.url = url;\n    this.ip = remoteAddress;\n\n    this._read = () => {\n      this.push(body);\n      this.push(null);\n    };\n  }\n\n  ip?: string;\n  body?: Buffer | Uint8Array;\n}\n"
  },
  {
    "path": "src/network/response-stream.ts",
    "content": "import { ServerResponse } from 'node:http';\nimport type { Socket } from 'node:net';\nimport type { Writable } from 'node:stream';\nimport type { BothValueHeaders } from '../@types';\nimport { type ILogger, NO_OP, parseHeaders } from '../core';\nimport { getString } from './utils';\n\n// header or data crlf\nconst crlfBuffer = Buffer.from('\\r\\n');\n\nconst endChunked = '0\\r\\n\\r\\n';\nconst headerEnd = '\\r\\n\\r\\n';\nconst endStatusSeparator = '\\r\\n';\n\n/**\n * The properties to create a {@link ServerlessStreamResponse}.\n *\n * @breadcrumb Network / ServerlessStreamResponse\n * @public\n */\nexport interface ServerlessStreamResponseProps {\n  /**\n   * The HTTP Method from request\n   */\n  method?: string;\n\n  /**\n   * The callback to receive the headers when they are written to the stream\n   * You need to return a writable stream be able to continue writing the response\n   *\n   * @param statusCode - The status code of the response\n   * @param headers - The headers of the response\n   */\n  onReceiveHeaders: (statusCode: number, headers: BothValueHeaders) => Writable;\n\n  /**\n   * Instance of the logger\n   */\n  log: ILogger;\n}\n\n/**\n * The class that represents a response instance used to send to the framework and wait until the framework finishes processing the request.\n * This response is specially built to deal with transfer-encoding: chunked\n *\n * @breadcrumb Network / ServerlessStreamResponse\n * @public\n */\nexport class ServerlessStreamResponse extends ServerResponse {\n  constructor({\n    method,\n    onReceiveHeaders,\n    log,\n  }: ServerlessStreamResponseProps) {\n    super({ method } as any);\n\n    this.useChunkedEncodingByDefault = true;\n    this.chunkedEncoding = true;\n\n    let internalWritable: Writable | null = null;\n    let firstCrlfBufferEncountered = false;\n    let chunkEncountered = false;\n\n    const socket: Partial<Socket> & { _writableState: any } = {\n      _writableState: {},\n      writable: true,\n      on: NO_OP,\n      removeListener: NO_OP,\n      destroy: NO_OP,\n      cork: NO_OP,\n      uncork: NO_OP,\n      write: (\n        data: Uint8Array | string,\n        encoding?: string | null | (() => void),\n        cb?: () => void,\n      ): any => {\n        // very unlikely, I don't even know how to reproduce this, but exist on types\n        // istanbul ignore if\n        if (typeof encoding === 'function') {\n          cb = encoding;\n          encoding = null;\n        }\n\n        log.debug('SERVERLESS_ADAPTER:RESPONSE_STREAM:DATA', () => ({\n          data: Buffer.isBuffer(data) ? data.toString('utf8') : data,\n          encoding,\n        }));\n\n        if (!internalWritable) {\n          const stringData = getString(data);\n          const endStatusIndex = stringData.indexOf(endStatusSeparator);\n          const status = +stringData.slice(0, endStatusIndex).split(' ')[1];\n          const endHeaderIndex = stringData.indexOf(headerEnd);\n\n          const headerData = stringData.slice(\n            endStatusIndex + 2,\n            endHeaderIndex,\n          );\n          const headers = parseHeaders(headerData);\n          log.debug(\n            'SERVERLESS_ADAPTER:RESPONSE_STREAM:FRAMEWORK_HEADERS',\n            () => ({\n              headers,\n            }),\n          );\n\n          internalWritable = onReceiveHeaders(status, headers);\n\n          // If we get an endChunked right after header which means the response body is empty, we need to immediately end the writable\n          if (stringData.substring(endHeaderIndex + 4) === endChunked)\n            internalWritable.end();\n\n          return true;\n        }\n\n        // node sends the last chunk crlf as a string:\n        // https://github.com/nodejs/node/blob/v22.8.0/lib/_http_outgoing.js#L1131\n        if (data === endChunked) {\n          internalWritable.end(cb);\n          return true;\n        }\n\n        // check for header or data crlf\n        // node sends the header and data crlf as a buffer\n        // below code is aligned to following node implementation of the HTTP/1.1 chunked transfer coding:\n        // https://github.com/nodejs/node/blob/v22.8.0/lib/_http_outgoing.js#L1012-L1015\n        // for reference: https://datatracker.ietf.org/doc/html/rfc9112#section-7\n        if (Buffer.isBuffer(data) && crlfBuffer.equals(data)) {\n          const isHeaderCrlf = !firstCrlfBufferEncountered;\n          if (isHeaderCrlf) {\n            firstCrlfBufferEncountered = true;\n            return true;\n          }\n\n          const isDataCrlf = firstCrlfBufferEncountered && chunkEncountered;\n          if (isDataCrlf) {\n            // done with chunk\n            firstCrlfBufferEncountered = false;\n            chunkEncountered = false;\n            return true;\n          }\n\n          // the crlf *is* the chunk\n        }\n\n        const isContentLength = !firstCrlfBufferEncountered;\n        if (isContentLength) {\n          // discard content length\n          return true;\n        }\n\n        // write chunk\n        chunkEncountered = true;\n        internalWritable.write(data, cb);\n        return true;\n      },\n    };\n\n    this.assignSocket(socket as unknown as Socket);\n  }\n}\n"
  },
  {
    "path": "src/network/response.ts",
    "content": "// ATTRIBUTION: https://github.com/dougmoscrop/serverless-http\nimport { IncomingMessage, ServerResponse } from 'node:http';\nimport type { Socket } from 'node:net';\nimport { NO_OP } from '../core';\nimport { getString } from './utils';\n\nconst headerEnd = '\\r\\n\\r\\n';\nconst endChunked = '0\\r\\n\\r\\n';\n\nconst BODY = Symbol('Response body');\nconst HEADERS = Symbol('Response headers');\n\nfunction addData(stream: ServerlessResponse, data: Uint8Array | string) {\n  if (\n    Buffer.isBuffer(data) ||\n    typeof data === 'string' ||\n    data instanceof Uint8Array\n  )\n    stream[BODY].push(Buffer.from(data));\n  else throw new Error(`response.write() of unexpected type: ${typeof data}`);\n}\n\n/**\n * The properties to create a {@link ServerlessResponse}.\n *\n * @breadcrumb Network / ServerlessResponse\n * @public\n */\nexport interface ServerlessResponseProps {\n  /**\n   * The HTTP Method from request\n   */\n  method?: string;\n}\n\n/**\n * The class that represents a response instance used to send to the framework and wait until the framework finishes processing the request.\n * Once it's happens, we use the properties from this response to built the response to the cloud.\n *\n * @breadcrumb Network / ServerlessResponse\n * @public\n */\nexport class ServerlessResponse extends ServerResponse {\n  constructor({ method }: ServerlessResponseProps) {\n    super({ method } as any);\n\n    this[BODY] = [];\n    this[HEADERS] = {};\n\n    this.useChunkedEncodingByDefault = false;\n    this.chunkedEncoding = false;\n    this._header = '';\n\n    // this ignore is used because I need to ignore these write calls:\n    // https://github.com/nodejs/node/blob/main/lib/_http_outgoing.js#L934-L935\n    // https://github.com/nodejs/node/blob/main/lib/_http_outgoing.js#L937\n    let writesToIgnore = 1;\n\n    const socket: Partial<Socket> & { _writableState: any } = {\n      _writableState: {},\n      writable: true,\n      on: NO_OP,\n      removeListener: NO_OP,\n      destroy: NO_OP,\n      cork: NO_OP,\n      uncork: NO_OP,\n      write: (\n        data: Uint8Array | string,\n        encoding?: string | null | (() => void),\n        cb?: () => void,\n      ): any => {\n        if (typeof encoding === 'function') {\n          cb = encoding;\n          encoding = null;\n        }\n\n        if (this._header === '' || this._wroteHeader) {\n          if (!this.chunkedEncoding) addData(this, data);\n          else {\n            if (writesToIgnore > 0) writesToIgnore--;\n            else if (data !== endChunked) {\n              addData(this, data);\n              writesToIgnore = 3;\n            }\n          }\n        } else {\n          const string = getString(data);\n          const index = string.indexOf(headerEnd);\n\n          if (index !== -1) {\n            const remainder = string.slice(index + headerEnd.length);\n\n            if (remainder && !this.chunkedEncoding) addData(this, remainder);\n\n            this._wroteHeader = true;\n          }\n        }\n\n        if (typeof cb === 'function') cb();\n      },\n    };\n\n    this.assignSocket(socket as unknown as Socket);\n  }\n\n  _header: string;\n  _headers?: Record<any, any>;\n  _wroteHeader?: boolean;\n\n  [BODY]: any[];\n  [HEADERS]: Record<any, any>;\n\n  get headers(): Record<any, any> {\n    return this[HEADERS];\n  }\n\n  static from(res: IncomingMessage) {\n    const response = new ServerlessResponse({ method: res.method });\n\n    response.statusCode = res.statusCode || 0;\n    response[HEADERS] = res.headers;\n    response[BODY] = (res as any).body ? [Buffer.from((res as any).body)] : [];\n    response.end();\n\n    return response;\n  }\n\n  static body(res: ServerlessResponse): Buffer {\n    return Buffer.concat(res[BODY]);\n  }\n\n  static headers(res: ServerlessResponse) {\n    const headers = res.getHeaders();\n\n    return Object.assign(headers, res[HEADERS]);\n  }\n\n  override setHeader(\n    key: string,\n    value: number | string | readonly string[],\n  ): any {\n    if (this._wroteHeader) this[HEADERS][key] = value;\n    else super.setHeader(key, value);\n  }\n\n  override writeHead(\n    statusCode: number,\n    statusMessage?: string | any | any[],\n    obj?: any | any[],\n  ): any {\n    const headersObjOrArray =\n      typeof statusMessage === 'string' ? obj : statusMessage;\n\n    const arrayHeaders = Array.isArray(headersObjOrArray)\n      ? headersObjOrArray\n      : [headersObjOrArray || {}];\n\n    for (const headers of arrayHeaders) {\n      for (const name in headers) {\n        this.setHeader(name, headers[name]!);\n\n        if (!this._wroteHeader) {\n          // we only need to initiate super.headers once\n          // writeHead will add the other headers itself\n          break;\n        }\n      }\n    }\n\n    return this.callNativeWriteHead(statusCode, statusMessage, obj);\n  }\n\n  /**\n   * I use ignore here because in nodejs 12.x, statusMessage can be string | OutgoingHttpHeaders\n   * But in nodejs \\>=14.x, statusMessage can also be OutgoingHttpHeaders[]\n   * I take care of these cases above, but here I can't handle it well, so I give up\n   * nodejs 12.x ref: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/v12/http.d.ts#L229\n   * nodejs 14.x ref: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/v14/http.d.ts#L263\n   */\n  protected callNativeWriteHead(\n    statusCode: number,\n    statusMessage?: string | any | any[],\n    obj?: any | any[],\n  ): this {\n    return super.writeHead(statusCode, statusMessage, obj);\n  }\n}\n"
  },
  {
    "path": "src/network/utils.ts",
    "content": "/**\n * Get the data from a buffer, string, or Uint8Array\n *\n * @breadcrumb Network\n * @param data - The data that was written inside the stream\n */\nexport function getString(data: Buffer | string | unknown) {\n  if (Buffer.isBuffer(data)) return data.toString('utf8');\n  else if (typeof data === 'string') return data;\n  else if (data instanceof Uint8Array) return new TextDecoder().decode(data);\n  else throw new Error(`response.write() of unexpected type: ${typeof data}`);\n}\n"
  },
  {
    "path": "src/resolvers/aws-context/aws-context.resolver.ts",
    "content": "//#region Imports\n\nimport type { Context } from 'aws-lambda';\nimport type {\n  DelegatedResolver,\n  Resolver,\n  ResolverContract,\n  ResolverProps,\n} from '../../contracts';\n\n//#endregion\n\n/**\n * The class that implements the resolver by using the AWS Context object.\n *\n * @remarks To use this resolver, you MUST leave `{@link https://docs.aws.amazon.com/lambda/latest/dg/nodejs-context.html | callbackWaitsForEmptyEventLoop}` as true, otherwise, AWS will not wait for this resolver to resolve.\n *\n * @deprecated From the AWS Documentation, describing the functions used in this resolver: Functions for compatibility with earlier Node.js Runtime v0.10.42. No longer documented, so they are deprecated, but they still work as of the 12.x runtime, so they are not removed from the types.\n *\n * @breadcrumb Resolvers / AwsContextResolver\n * @public\n */\nexport class AwsContextResolver<TEvent, TCallback, TResponse>\n  implements ResolverContract<TEvent, Context, TCallback, TResponse, void>\n{\n  /**\n   * {@inheritDoc}\n   */\n  public createResolver({\n    context,\n    event,\n    log,\n    respondWithErrors,\n    adapter,\n  }: ResolverProps<any, Context, any, any>): Resolver<any, void> {\n    if (!context) {\n      throw new Error(\n        'Could not figure out how to create the resolver because the \"context\" argument was not sent.',\n      );\n    }\n\n    if (!context.succeed) {\n      throw new Error(\n        'Could not figure out how to create the resolver because the \"context\" argument didn\\'t have the \"succeed\" function.',\n      );\n    }\n\n    if (!context.fail) {\n      throw new Error(\n        'Could not figure out how to create the resolver because the \"context\" argument didn\\'t have the \"fail\" function.',\n      );\n    }\n\n    const delegatedResolver: DelegatedResolver<any> = {\n      succeed: response => context.succeed(response),\n      fail: error => context.fail(error),\n    };\n\n    return {\n      run: task => {\n        task()\n          .then(response => delegatedResolver.succeed(response))\n          .catch(error => {\n            log.error(\n              'SERVERLESS_ADAPTER:RESPOND_TO_EVENT_SOURCE_WITH_ERROR',\n              error,\n            );\n\n            adapter.onErrorWhileForwarding({\n              delegatedResolver,\n              error,\n              log,\n              event,\n              respondWithErrors,\n            });\n          });\n      },\n    };\n  }\n}\n"
  },
  {
    "path": "src/resolvers/aws-context/index.ts",
    "content": "export * from './aws-context.resolver';\n"
  },
  {
    "path": "src/resolvers/callback/callback.resolver.ts",
    "content": "//#region Imports\n\nimport type {\n  DelegatedResolver,\n  Resolver,\n  ResolverContract,\n  ResolverProps,\n} from '../../contracts';\n\n//#endregion\n\n/**\n * The default signature of the callback sent by serverless\n *\n * @breadcrumb Resolvers / CallbackResolver\n * @public\n */\nexport type ServerlessCallback<TResponse> = (\n  error: Error | null,\n  success: TResponse | null,\n) => void;\n\n/**\n * The class that implements the resolver using the callback function sent by serverless\n *\n * @remarks To use this resolver on AWS, you MUST leave `{@link https://docs.aws.amazon.com/lambda/latest/dg/nodejs-context.html | callbackWaitsForEmptyEventLoop}` as true, otherwise, AWS will not wait for this resolver to resolve.\n *\n * @breadcrumb Resolvers / CallbackResolver\n * @public\n */\nexport class CallbackResolver<TEvent, TContext, TResponse>\n  implements\n    ResolverContract<TEvent, TContext, ServerlessCallback<any>, TResponse, void>\n{\n  /**\n   * {@inheritDoc}\n   */\n  public createResolver({\n    callback,\n    event,\n    log,\n    respondWithErrors,\n    adapter,\n  }: ResolverProps<\n    TEvent,\n    TContext,\n    ServerlessCallback<any>,\n    TResponse\n  >): Resolver<any, void> {\n    if (!callback) {\n      throw new Error(\n        'Could not figure out how to create the resolver because the \"callback\" argument was not sent.',\n      );\n    }\n\n    const delegatedResolver: DelegatedResolver<any> = {\n      succeed: response => callback(null, response),\n      fail: error => callback(error, null),\n    };\n\n    return {\n      run: task => {\n        task()\n          .then(response => delegatedResolver.succeed(response))\n          .catch(error => {\n            log.error(\n              'SERVERLESS_ADAPTER:RESPOND_TO_EVENT_SOURCE_WITH_ERROR',\n              error,\n            );\n\n            adapter.onErrorWhileForwarding({\n              delegatedResolver,\n              error,\n              log,\n              event,\n              respondWithErrors,\n            });\n          });\n      },\n    };\n  }\n}\n"
  },
  {
    "path": "src/resolvers/callback/index.ts",
    "content": "export * from './callback.resolver';\n"
  },
  {
    "path": "src/resolvers/dummy/dummy.resolver.ts",
    "content": "//#region Imports\n\nimport type { Resolver, ResolverContract } from '../../contracts';\n\n//#endregion\n\n/**\n * The class that represents a dummy resolver that does nothing and can be used by the cloud that doesn't use resolvers.\n *\n * @breadcrumb Resolvers / DummyResolver\n * @public\n */\nexport class DummyResolver\n  implements ResolverContract<any, any, any, any, any>\n{\n  /**\n   * {@inheritDoc}\n   */\n  public createResolver(): Resolver<any, void> {\n    return {\n      // eslint-disable-next-line @typescript-eslint/no-misused-promises\n      run: () => Promise.resolve(),\n    };\n  }\n}\n"
  },
  {
    "path": "src/resolvers/dummy/index.ts",
    "content": "export * from './dummy.resolver';\n"
  },
  {
    "path": "src/resolvers/promise/index.ts",
    "content": "export * from './promise.resolver';\n"
  },
  {
    "path": "src/resolvers/promise/promise.resolver.ts",
    "content": "//#region Imports\n\nimport type {\n  DelegatedResolver,\n  Resolver,\n  ResolverContract,\n  ResolverProps,\n} from '../../contracts';\n\n//#endregion\n\n/**\n * The class that implements the resolver using the promise object sent by this library\n *\n * @breadcrumb Resolvers / PromiseResolver\n * @public\n */\nexport class PromiseResolver<TEvent, TContext, TCallback, TResponse, TReturn>\n  implements\n    ResolverContract<TEvent, TContext, TCallback, TResponse, Promise<any>>\n{\n  /**\n   * {@inheritDoc}\n   */\n  public createResolver({\n    event,\n    log,\n    respondWithErrors,\n    adapter,\n  }: ResolverProps<TEvent, TContext, TCallback, TResponse>): Resolver<\n    TResponse,\n    Promise<TReturn>\n  > {\n    return {\n      run: task => {\n        return new Promise((resolve, reject) => {\n          const delegatedResolver: DelegatedResolver<any> = {\n            succeed: response => resolve(response),\n            fail: error => reject(error),\n          };\n\n          task()\n            .then(response => delegatedResolver.succeed(response))\n            .catch(error => {\n              log.error(\n                'SERVERLESS_ADAPTER:RESPOND_TO_EVENT_SOURCE_WITH_ERROR',\n                error,\n              );\n\n              adapter.onErrorWhileForwarding({\n                delegatedResolver,\n                error,\n                log,\n                event,\n                respondWithErrors,\n              });\n            });\n        });\n      },\n    };\n  }\n}\n"
  },
  {
    "path": "src/serverless-adapter.ts",
    "content": "//#region Imports\n\nimport type { BinarySettings } from './@types';\nimport type {\n  AdapterContract,\n  FrameworkContract,\n  HandlerContract,\n  ResolverContract,\n  ServerlessHandler,\n} from './contracts';\nimport {\n  DEFAULT_BINARY_CONTENT_TYPES,\n  DEFAULT_BINARY_ENCODINGS,\n  type ILogger,\n  createDefaultLogger,\n} from './core';\n\n//#endregion\n\n/**\n * The class used to build the serverless handler.\n *\n * @example\n * ```typescript\n * const app = express();\n * export const handler = ServerlessAdapter.new(app)\n *   .setFramework(new ExpressFramework())\n *   .setHandler(new DefaultHandler())\n *   .setResolver(new PromiseResolver())\n *   .setRespondWithErrors(true)\n *   .addAdapter(new AlbAdapter())\n *   .addAdapter(new SQSAdapter())\n *   .addAdapter(new SNSAdapter())\n *   .build();\n * ```\n *\n * @breadcrumb ServerlessAdapter\n * @public\n */\nexport class ServerlessAdapter<\n  TApp,\n  TEvent,\n  TContext,\n  TCallback,\n  TResponse,\n  TReturn,\n> {\n  //#region Constructor\n\n  /**\n   * Default constructor\n   */\n  private constructor(app: TApp) {\n    this.app = app;\n  }\n\n  //#endregion\n\n  //#region Protected Properties\n\n  /**\n   * The instance of the app (express, hapi, koa, etc...)\n   */\n  protected app: TApp;\n\n  //#endregion\n\n  //#region Protected Properties\n\n  /**\n   * Settings for whether the response should be treated as binary or not\n   *\n   * @defaultValue `contentEncodings` and `contentTypes` are set with {@link DEFAULT_BINARY_ENCODINGS} and {@link DEFAULT_BINARY_CONTENT_TYPES}, respectively.\n   */\n  protected binarySettings: BinarySettings = {\n    contentEncodings: DEFAULT_BINARY_ENCODINGS,\n    contentTypes: DEFAULT_BINARY_CONTENT_TYPES,\n  };\n\n  /**\n   * Indicates whether the error stack should be included in the response or not\n   *\n   * @remarks These errors will only be included when an error occurs while forwarding the event to the framework\n   * @defaultValue True when NODE_ENV is equal to `development`\n   */\n  protected respondWithErrors: boolean = process.env.NODE_ENV === 'development';\n\n  /**\n   * The instance of the logger service\n   */\n  protected log: ILogger = createDefaultLogger();\n\n  /**\n   * The list of adapters used to handle an event's request and response\n   */\n  protected adapters: AdapterContract<TEvent, TContext, TResponse>[] = [];\n\n  /**\n   * The framework that will process requests\n   */\n  protected framework?: FrameworkContract<TApp>;\n\n  /**\n   * The resolver that aims to resolve the response to serverless and stop its execution when the request ends\n   */\n  protected resolver?: ResolverContract<\n    TEvent,\n    TContext,\n    TCallback,\n    TResponse,\n    TReturn\n  >;\n\n  /**\n   * The handler that will get the event, context and callback and pass it to the adapter and framework\n   */\n  protected handler?: HandlerContract<\n    TApp,\n    TEvent,\n    TContext,\n    TCallback,\n    TResponse,\n    TReturn\n  >;\n\n  //#endregion\n\n  //#region Static Methods\n\n  /**\n   * Creates a new instance of the builder with app (express, hapi, koa, etc...)\n   *\n   * @param app - The instance of the app\n   */\n  public static new<\n    TApp,\n    TEvent,\n    TContext = any,\n    TCallback = any,\n    TResponse = any,\n    TReturn = any,\n  >(\n    app: TApp,\n  ): ServerlessAdapter<TApp, TEvent, TContext, TCallback, TResponse, TReturn> {\n    return new ServerlessAdapter(app);\n  }\n\n  //#endregion\n\n  //#region Builder Methods\n\n  /**\n   * Defines the handler that will get the event, context and callback and pass it to the adapter and framework\n   *\n   * @param handler - The implementation of the handler contract\n   */\n  public setHandler(\n    handler: HandlerContract<\n      TApp,\n      TEvent,\n      TContext,\n      TCallback,\n      TResponse,\n      TReturn\n    >,\n  ): Omit<this, 'setHandler'> {\n    if (this.handler)\n      throw new Error('SERVERLESS_ADAPTER: The handler should not set twice.');\n\n    this.handler = handler;\n\n    return this;\n  }\n\n  /**\n   * Defines the resolver that aims to resolve the response to serverless and stop its execution when the request ends\n   *\n   * @param resolver - The implementation of the resolver contract\n   */\n  public setResolver(\n    resolver: ResolverContract<TEvent, TContext, TCallback, TResponse, TReturn>,\n  ): Omit<this, 'setResolver'> {\n    if (this.resolver)\n      throw new Error('SERVERLESS_ADAPTER: The resolver should not set twice.');\n\n    this.resolver = resolver;\n\n    return this;\n  }\n\n  /**\n   * Defines the framework that will process requests\n   *\n   * @param framework - The implementation of the framework contract\n   */\n  public setFramework(\n    framework: FrameworkContract<TApp>,\n  ): Omit<this, 'setFramework'> {\n    if (this.framework) {\n      throw new Error(\n        'SERVERLESS_ADAPTER: The framework should not set twice.',\n      );\n    }\n\n    this.framework = framework;\n\n    return this;\n  }\n\n  /**\n   * Defines the logger service used during the execution of the handler\n   *\n   * @param logger - The implementation of the logger\n   */\n  public setLogger(logger: ILogger): Omit<this, 'setLogger'> {\n    this.log = logger;\n\n    return this;\n  }\n\n  /**\n   * Defines the binary settings for whether the response should be treated as binary or not\n   *\n   * @param binarySettings - The binary settings\n   */\n  public setBinarySettings(\n    binarySettings: BinarySettings,\n  ): Omit<this, 'setBinarySettings'> {\n    this.binarySettings = {\n      ...this.binarySettings,\n      ...binarySettings,\n    };\n\n    return this;\n  }\n\n  /**\n   * Defines the responseWithErrors, a property that indicates whether the error stack should be included in the response or not\n   *\n   * @param respondWithErrors - Should include or not the errors in response\n   */\n  public setRespondWithErrors(\n    respondWithErrors: boolean,\n  ): Omit<this, 'setRespondWithErrors'> {\n    this.respondWithErrors = respondWithErrors;\n\n    return this;\n  }\n\n  /**\n   * Add an adapter to the adapters list to handle the event coming from any serverless event source\n   *\n   * @param adapter - The implementation of the adapter contract\n   */\n  public addAdapter(\n    adapter: AdapterContract<TEvent, TContext, TResponse>,\n  ): Pick<this, 'addAdapter' | 'build'> {\n    this.adapters.push(adapter);\n\n    return this;\n  }\n\n  /**\n   * The builder method that returns the handler function to be exported for serverless consumption\n   */\n  public build(): ServerlessHandler<TReturn> {\n    if (!this.resolver) {\n      throw new Error(\n        'SERVERLESS_ADAPTER: Is required to set a resolver before build.',\n      );\n    }\n\n    if (!this.framework) {\n      throw new Error(\n        'SERVERLESS_ADAPTER: Is required to set a framework before build.',\n      );\n    }\n\n    if (!this.handler) {\n      throw new Error(\n        'SERVERLESS_ADAPTER: Is required to set a handler before build.',\n      );\n    }\n\n    if (this.adapters.length === 0) {\n      throw new Error(\n        'SERVERLESS_ADAPTER: Is required to set at least one adapter.',\n      );\n    }\n\n    return this.handler.getHandler(\n      this.app,\n      this.framework,\n      this.adapters,\n      this.resolver,\n      this.binarySettings,\n      this.respondWithErrors,\n      this.log,\n    );\n  }\n\n  //#endregion\n}\n"
  },
  {
    "path": "test/adapters/apollo-server/apollo-mutation.adapter.spec.ts",
    "content": "import { ApolloServer } from '@apollo/server';\nimport { describe, expect, it, vitest } from 'vitest';\nimport type { SQSEvent } from 'aws-lambda';\nimport {\n  type AdapterContract,\n  EmptyResponse,\n  type GetResponseAdapterProps,\n  ServerlessRequest,\n  ServerlessResponse,\n  createDefaultLogger,\n  waitForStreamComplete,\n} from '../../../src';\nimport {\n  ApolloServerMutationAdapter,\n  type ApolloServerMutationAdapterOptions,\n} from '../../../src/adapters/apollo-server';\nimport {\n  DynamoDBAdapter,\n  SNSAdapter,\n  SQSAdapter,\n} from '../../../src/adapters/aws';\nimport { ApolloServerFramework } from '../../../src/frameworks/apollo-server';\nimport { JsonBodyParserFramework } from '../../../src/frameworks/body-parser';\nimport { createDynamoDBEvent } from '../aws/utils/dynamodb';\nimport { createSNSEvent } from '../aws/utils/sns';\nimport { createSQSEvent } from '../aws/utils/sqs';\n\nfunction createApolloServer({\n  mutationName,\n  queryDefinition,\n}: {\n  mutationName: string;\n  queryDefinition: string;\n}): ApolloServer {\n  const schema = `\n    type Query { message: String }\n\n    type AWSResult ${queryDefinition}\n\n    type Mutation {\n      ${mutationName} (event: String): AWSResult\n    }\n  `;\n\n  const app = new ApolloServer({\n    typeDefs: schema,\n    resolvers: {\n      Query: {\n        message: () => 'Hello World!',\n      },\n      Mutation: {\n        [mutationName]: (_, data) => {\n          return {\n            result: data.event,\n          };\n        },\n      },\n    },\n  });\n\n  app.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests();\n\n  return app;\n}\n\nconst options: [adapter: AdapterContract<any, any, any>, eventData: any][] = [\n  [new SQSAdapter(), createSQSEvent()],\n  [new SNSAdapter(), createSNSEvent()],\n  [new DynamoDBAdapter(), createDynamoDBEvent()],\n];\n\ndescribe('integration: should be able to convert', () => {\n  for (const [adapter, eventData] of options) {\n    it(`${adapter.getAdapterName()}: should convert correctly`, async () => {\n      const options: ApolloServerMutationAdapterOptions = {\n        mutationName: 'aws',\n        mutationResultQuery: '{ result }',\n      };\n\n      const app = createApolloServer({\n        mutationName: 'aws',\n        queryDefinition: '{ result: String }',\n      });\n\n      const mutationAdapter = new ApolloServerMutationAdapter(adapter, options);\n\n      expect(\n        mutationAdapter.canHandle(eventData, null, createDefaultLogger()),\n      ).toEqual(true);\n\n      const request = mutationAdapter.getRequest(\n        eventData,\n        null,\n        createDefaultLogger(),\n      );\n\n      expect(request.method).toEqual('POST');\n\n      const serverlessRequest = new ServerlessRequest({\n        method: request.method,\n        headers: request.headers,\n        body: request.body,\n        remoteAddress: request.remoteAddress,\n        url: request.path,\n      });\n\n      const serverlessResponse = new ServerlessResponse({\n        method: request.method,\n      });\n\n      const framework = new JsonBodyParserFramework(\n        new ApolloServerFramework(),\n      );\n\n      framework.sendRequest(app, serverlessRequest, serverlessResponse);\n\n      await waitForStreamComplete(serverlessResponse);\n\n      expect(ServerlessResponse.body(serverlessResponse).toString()).toContain(\n        JSON.stringify({\n          data: {\n            aws: {\n              result: JSON.stringify(eventData),\n            },\n          },\n        }),\n      );\n\n      const sqsAdapterSpy = vitest.spyOn(adapter, 'getResponse');\n\n      const props = {\n        response: serverlessResponse,\n        body: ServerlessResponse.body(serverlessResponse).toString(),\n        headers: ServerlessResponse.headers(serverlessResponse),\n        log: createDefaultLogger(),\n        event: eventData,\n        statusCode: serverlessResponse.statusCode,\n        isBase64Encoded: false,\n      };\n      const response = mutationAdapter.getResponse(props);\n\n      expect(sqsAdapterSpy).toHaveBeenNthCalledWith(\n        1,\n        expect.objectContaining({\n          ...props,\n          body: JSON.stringify({\n            result: JSON.stringify(eventData),\n          }),\n        }),\n      );\n      expect(response).toEqual(EmptyResponse);\n    });\n  }\n\n  it('to __typename: when result query is not passed', async () => {\n    const options: ApolloServerMutationAdapterOptions = {\n      mutationName: 'aws',\n    };\n\n    const eventData = createSQSEvent();\n    const adapter: AdapterContract<any, any, any> = new SQSAdapter();\n    const app = createApolloServer({\n      mutationName: 'aws',\n      queryDefinition: '{_: Boolean}',\n    });\n\n    const mutationAdapter = new ApolloServerMutationAdapter(adapter, options);\n    const request = mutationAdapter.getRequest(\n      eventData,\n      null,\n      createDefaultLogger(),\n    );\n    const serverlessRequest = new ServerlessRequest({\n      method: request.method,\n      headers: request.headers,\n      body: request.body,\n      remoteAddress: request.remoteAddress,\n      url: request.path,\n    });\n\n    const serverlessResponse = new ServerlessResponse({\n      method: request.method,\n    });\n    const framework = new JsonBodyParserFramework(new ApolloServerFramework());\n\n    framework.sendRequest(app, serverlessRequest, serverlessResponse);\n    await waitForStreamComplete(serverlessResponse);\n\n    const sqsAdapterSpy = vitest.spyOn(adapter, 'getResponse');\n\n    const props = {\n      response: serverlessResponse,\n      body: ServerlessResponse.body(serverlessResponse).toString(),\n      headers: ServerlessResponse.headers(serverlessResponse),\n      log: createDefaultLogger(),\n      event: eventData,\n      statusCode: serverlessResponse.statusCode,\n      isBase64Encoded: false,\n    };\n    const response = mutationAdapter.getResponse(props);\n\n    expect(sqsAdapterSpy).toHaveBeenNthCalledWith(\n      1,\n      expect.objectContaining({\n        ...props,\n        body: JSON.stringify({ __typename: 'AWSResult' }),\n      }),\n    );\n    expect(response).toEqual(EmptyResponse);\n  });\n\n  it('to base adapter: when mutation does not exist', async () => {\n    const options: ApolloServerMutationAdapterOptions = {\n      mutationName: 'aws',\n    };\n\n    const eventData = createSQSEvent();\n    const adapter: AdapterContract<any, any, any> = new SQSAdapter();\n    const app = createApolloServer({\n      mutationName: 'potato',\n      queryDefinition: '{_: Boolean}',\n    });\n\n    const mutationAdapter = new ApolloServerMutationAdapter(adapter, options);\n    const request = mutationAdapter.getRequest(\n      eventData,\n      null,\n      createDefaultLogger(),\n    );\n    const serverlessRequest = new ServerlessRequest({\n      method: request.method,\n      headers: request.headers,\n      body: request.body,\n      remoteAddress: request.remoteAddress,\n      url: request.path,\n    });\n\n    const serverlessResponse = new ServerlessResponse({\n      method: request.method,\n    });\n    const framework = new JsonBodyParserFramework(new ApolloServerFramework());\n\n    framework.sendRequest(app, serverlessRequest, serverlessResponse);\n    await waitForStreamComplete(serverlessResponse);\n\n    const sqsAdapterSpy = vitest.spyOn(adapter, 'getResponse');\n\n    const props = {\n      response: serverlessResponse,\n      body: ServerlessResponse.body(serverlessResponse).toString(),\n      headers: ServerlessResponse.headers(serverlessResponse),\n      log: createDefaultLogger(),\n      event: eventData,\n      statusCode: serverlessResponse.statusCode,\n      isBase64Encoded: false,\n    };\n\n    expect(() => mutationAdapter.getResponse(props)).toThrow(\n      'Cannot query field',\n    );\n    expect(sqsAdapterSpy).toHaveBeenNthCalledWith(1, props);\n  });\n});\n\nit('getAdapterName: should mutate the name of adapter', () => {\n  const sqs = new SQSAdapter();\n  const mutation = new ApolloServerMutationAdapter(sqs, {\n    mutationName: 'aws',\n  });\n\n  expect(mutation.getAdapterName()).toEqual(`${sqs.getAdapterName()}Mutation`);\n});\n\nit('onErrorWhileForwarding: should forward error dealing to base adapter', () => {\n  const sqs = new SQSAdapter();\n  const spyedOnError = vitest.spyOn(sqs, 'onErrorWhileForwarding');\n\n  const mutation = new ApolloServerMutationAdapter(sqs, {\n    mutationName: 'aws',\n  });\n\n  const props = {\n    event: {} as SQSEvent,\n    log: createDefaultLogger(),\n    error: new Error(),\n    delegatedResolver: { fail: vitest.fn(), succeed: vitest.fn() },\n    respondWithErrors: true,\n  };\n\n  mutation.onErrorWhileForwarding(props);\n\n  expect(spyedOnError).toHaveBeenNthCalledWith(1, props);\n});\n\nit('getResponse: should forward props to base adapter when response has errors', () => {\n  const sqs = new SQSAdapter();\n  const spyedOnError = vitest.spyOn(sqs, 'getResponse');\n\n  const mutation = new ApolloServerMutationAdapter(sqs, {\n    mutationName: 'aws',\n  });\n\n  const props: GetResponseAdapterProps<any> = {\n    log: createDefaultLogger(),\n    event: {},\n    body: JSON.stringify({ errors: { message: 'Wrong data' }, data: {} }),\n    isBase64Encoded: false,\n    statusCode: 400,\n    headers: {},\n  };\n\n  expect(() => mutation.getResponse(props)).toThrow('\"statusCode\":400');\n  expect(spyedOnError).toHaveBeenNthCalledWith(1, props);\n});\n"
  },
  {
    "path": "test/adapters/aws/alb.adapter.spec.ts",
    "content": "import type { ALBEvent, ALBResult } from 'aws-lambda';\nimport { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport {\n  type DelegatedResolver,\n  type GetResponseAdapterProps,\n  type ILogger,\n  getEventBodyAsBuffer,\n  getFlattenedHeadersMap,\n  getMultiValueHeadersMap,\n  getPathWithQueryStringParams,\n} from '../../../src';\nimport { AlbAdapter } from '../../../src/adapters/aws';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport {\n  createAlbEvent,\n  createAlbEventWithMultiValueHeaders,\n} from './utils/alb-event';\n\ndescribe(AlbAdapter.name, () => {\n  let adapter!: AlbAdapter;\n\n  beforeEach(() => {\n    adapter = new AlbAdapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(AlbAdapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(() => new AlbAdapter(), undefined);\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const method = 'PUT';\n      const path = '/events';\n      const body = { name: 'H4ad Event' };\n\n      const event = createAlbEvent(method, path, body);\n\n      expect(event.headers).toHaveProperty('x-forwarded-for');\n      expect(event.headers!['x-forwarded-for']).not.toBeInstanceOf(Array);\n\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.headers!['x-forwarded-for'];\n\n      expect(result).toHaveProperty('method', method);\n\n      expect(result).toHaveProperty('headers');\n      expect(result.headers).toHaveProperty('x-forwarded-for');\n      expect(result.headers['x-forwarded-for']).not.toBeInstanceOf(Array);\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).toBeInstanceOf(Buffer);\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(body),\n        false,\n      );\n      expect(result.body).toStrictEqual(bodyBuffer);\n      expect(result.headers).toHaveProperty('content-length');\n      expect(result.headers['content-length']).toBe(String(contentLength));\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path,\n        event.queryStringParameters,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n\n    it('should return the correct mapping for the request with multi value headers', () => {\n      const method = 'POST';\n      const path = '/events';\n      const body = { name: 'H4ad Event' };\n\n      const event = createAlbEventWithMultiValueHeaders(method, path, body);\n\n      expect(event.multiValueHeaders).toHaveProperty('x-forwarded-for');\n      expect(event.multiValueHeaders!['x-forwarded-for']).toBeInstanceOf(Array);\n\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.multiValueHeaders!['x-forwarded-for']![0];\n\n      expect(result).toHaveProperty('method', method);\n\n      expect(result).toHaveProperty('headers');\n      expect(result.headers).toHaveProperty('x-forwarded-for');\n      expect(result.headers['x-forwarded-for']).not.toBeInstanceOf(Array);\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).toBeInstanceOf(Buffer);\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(body),\n        false,\n      );\n      expect(result.body).toStrictEqual(bodyBuffer);\n      expect(result.headers).toHaveProperty('content-length');\n      expect(result.headers['content-length']).toBe(String(contentLength));\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path,\n        event.multiValueQueryStringParameters,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n\n    it('should return the correct mapping for the request when it has no body', () => {\n      const method = 'POST';\n      const path = '/events';\n      const body = undefined;\n\n      const event = createAlbEvent(method, path, body);\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.headers!['x-forwarded-for'];\n\n      expect(result).toHaveProperty('method', method);\n\n      expect(result).toHaveProperty('headers');\n      expect(result.headers).toHaveProperty('x-forwarded-for');\n      expect(result.headers['x-forwarded-for']).not.toBeInstanceOf(Array);\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).not.toBeInstanceOf(Buffer);\n      expect(result.body).toBeUndefined();\n\n      expect(result.headers).toHaveProperty('content-length');\n      expect(result.headers['content-length']).toBe(\n        event.headers!['content-length'],\n      );\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path,\n        event.queryStringParameters,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n\n    it('should return the correct mapping for the request when send stripBasePath', () => {\n      const stripBasePath = '/prod';\n\n      const method = 'PUT';\n      const path = '/prod/events';\n      const body = { name: 'H4ad Event' };\n\n      const strippedAdapter = new AlbAdapter({ stripBasePath });\n\n      const event = createAlbEvent(method, path, body);\n\n      expect(event.headers).toHaveProperty('x-forwarded-for');\n      expect(event.headers!['x-forwarded-for']).not.toBeInstanceOf(Array);\n\n      const result = strippedAdapter.getRequest(event);\n\n      const remoteAddress = event.headers!['x-forwarded-for'];\n\n      expect(result).toHaveProperty('method', method);\n\n      expect(result).toHaveProperty('headers');\n      expect(result.headers).toHaveProperty('x-forwarded-for');\n      expect(result.headers['x-forwarded-for']).not.toBeInstanceOf(Array);\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).toBeInstanceOf(Buffer);\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(body),\n        false,\n      );\n      expect(result.body).toStrictEqual(bodyBuffer);\n      expect(result.headers).toHaveProperty('content-length');\n      expect(result.headers['content-length']).toBe(String(contentLength));\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path.replace(stripBasePath, ''),\n        event.queryStringParameters,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n  });\n\n  describe('getResponse', () => {\n    it('should return the correct mapping for the response', () => {\n      const method = 'PUT';\n      const path = '/events';\n      const requestBody = { name: 'H4ad Event' };\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createAlbEvent(method, path, requestBody);\n      const responseHeaders = getFlattenedHeadersMap(event.headers!);\n\n      const result = adapter.getResponse({\n        event,\n        headers: responseHeaders,\n        body: resultBody,\n        log: {} as ILogger,\n        isBase64Encoded: resultIsBase64Encoded,\n        statusCode: resultStatusCode,\n      });\n\n      expect(result).toHaveProperty('statusCode', 200);\n      expect(result).toHaveProperty('body', resultBody);\n      expect(result).toHaveProperty('headers', responseHeaders);\n      expect(result).toHaveProperty('multiValueHeaders', undefined);\n      expect(result).toHaveProperty('isBase64Encoded', resultIsBase64Encoded);\n    });\n\n    it('should return the correct mapping for the response with multi value headers', () => {\n      const method = 'PUT';\n      const path = '/events';\n      const requestBody = { name: 'H4ad Event' };\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createAlbEventWithMultiValueHeaders(\n        method,\n        path,\n        requestBody,\n      );\n      const responseHeaders = getFlattenedHeadersMap(event.multiValueHeaders!);\n      const responseMultiValueHeaders =\n        getMultiValueHeadersMap(responseHeaders);\n\n      const result = adapter.getResponse({\n        event,\n        headers: responseHeaders,\n        body: resultBody,\n        log: {} as ILogger,\n        isBase64Encoded: resultIsBase64Encoded,\n        statusCode: resultStatusCode,\n      });\n\n      expect(result).toHaveProperty('statusCode', 200);\n      expect(result).toHaveProperty('body', resultBody);\n      expect(result).toHaveProperty('headers', undefined);\n      expect(result).toHaveProperty(\n        'multiValueHeaders',\n        responseMultiValueHeaders,\n      );\n      expect(result).toHaveProperty('isBase64Encoded', resultIsBase64Encoded);\n    });\n\n    it('should remove the transfer-encoding header if it is chunked', () => {\n      const event = createAlbEventWithMultiValueHeaders('GET', '/events');\n      const responseHeaders = getFlattenedHeadersMap(event.multiValueHeaders!);\n      const responseMultiValueHeaders =\n        getMultiValueHeadersMap(responseHeaders);\n\n      responseHeaders['transfer-encoding'] = 'chunked';\n\n      const result = adapter.getResponse({\n        event,\n        headers: responseHeaders,\n        body: '',\n        log: {} as ILogger,\n        isBase64Encoded: false,\n        statusCode: 200,\n      });\n\n      expect(result).toHaveProperty('headers', undefined);\n      expect(result).toHaveProperty(\n        'multiValueHeaders',\n        responseMultiValueHeaders,\n      );\n\n      responseMultiValueHeaders['transfer-encoding'] = ['chunked'];\n\n      const event2 = createAlbEvent('GET', '/events');\n      const responseHeaders2 = getFlattenedHeadersMap(event2.headers!);\n\n      const result2 = adapter.getResponse({\n        event: event2,\n        headers: responseHeaders2,\n        body: '',\n        log: {} as ILogger,\n        isBase64Encoded: false,\n        statusCode: 200,\n      });\n\n      expect(result2).toHaveProperty('headers', responseHeaders2);\n    });\n  });\n\n  describe('onErrorWhileForwarding', () => {\n    it('should resolver call succeed', () => {\n      const method = 'GET';\n      const path = '/events';\n      const requestBody = undefined;\n\n      const event = createAlbEventWithMultiValueHeaders(\n        method,\n        path,\n        requestBody,\n      );\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<ALBResult> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = true;\n      const error = new Error('Test error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: ALBResult | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<ALBEvent>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).toBe(error.stack);\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n\n    it('should resolver call succeed but without sending errors', () => {\n      const method = 'GET';\n      const path = '/events';\n      const requestBody = undefined;\n\n      const event = createAlbEventWithMultiValueHeaders(\n        method,\n        path,\n        requestBody,\n      );\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<ALBResult> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = false;\n      const error = new Error('Test error without sending this error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: ALBResult | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<ALBEvent>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).not.toBe(error.stack);\n          expect(params.body).toStrictEqual('');\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/aws/api-gateway-v1.adapter.spec.ts",
    "content": "import type { APIGatewayProxyResult } from 'aws-lambda';\nimport type { APIGatewayProxyEvent } from 'aws-lambda/trigger/api-gateway-proxy';\nimport { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport {\n  type DelegatedResolver,\n  type GetResponseAdapterProps,\n  type ILogger,\n  ServerlessResponse,\n  getEventBodyAsBuffer,\n  getFlattenedHeadersMap,\n  getMultiValueHeadersMap,\n  getPathWithQueryStringParams,\n} from '../../../src';\nimport { ApiGatewayV1Adapter } from '../../../src/adapters/aws';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport { createApiGatewayV1 } from './utils/api-gateway-v1';\n\ndescribe(ApiGatewayV1Adapter.name, () => {\n  let adapter!: ApiGatewayV1Adapter;\n\n  beforeEach(() => {\n    adapter = new ApiGatewayV1Adapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(ApiGatewayV1Adapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(() => new ApiGatewayV1Adapter(), undefined);\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const method = 'PUT';\n      const path = '/events';\n      const body = { name: 'H4ad Event' };\n\n      const event = createApiGatewayV1(method, path, body);\n      event.queryStringParameters = {\n        potato: 'v1',\n        nanana: 'oh nanana',\n        unkown: 'oi',\n        ignore: undefined,\n      };\n      event.multiValueQueryStringParameters = {\n        potato: ['v1', 'v2'],\n        nanana: ['oh nanana'],\n      };\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.requestContext.identity.sourceIp;\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n      expect(result.headers).toHaveProperty('Accept');\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).toBeInstanceOf(Buffer);\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(body),\n        false,\n      );\n      expect(result.body).toStrictEqual(bodyBuffer);\n      expect(result.headers).toHaveProperty('content-length');\n      expect(result.headers['content-length']).toBe(String(contentLength));\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path,\n        event.multiValueQueryStringParameters,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n\n    it('should return lowercase request headers if option `lowercaseRequestHeaders` is `true`', () => {\n      const method = 'GET';\n      const path = '/events';\n\n      adapter = new ApiGatewayV1Adapter({ lowercaseRequestHeaders: true });\n      const event = createApiGatewayV1(method, path);\n      event.headers['Cookie'] = 'test=test;';\n\n      const { headers } = adapter.getRequest(event);\n\n      expect(headers).not.toHaveProperty('Cookie');\n      expect(headers).toHaveProperty('cookie');\n      expect(headers).not.toHaveProperty('Accept');\n      expect(headers).toHaveProperty('accept');\n    });\n\n    it('should return the correct mapping for the request when it has no body', () => {\n      const method = 'GET';\n      const path = '/users';\n      const body = undefined;\n\n      const event = createApiGatewayV1(method, path, body, {}, { page: '2' });\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.requestContext.identity.sourceIp;\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).not.toBeInstanceOf(Buffer);\n      expect(result.body).toBeUndefined();\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path,\n        event.queryStringParameters,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n\n    it('should return the correct mapping for the request when send stripBasePath', () => {\n      const stripBasePath = '/prod';\n\n      const method = 'GET';\n      const path = '/prod/posts';\n      const body = undefined;\n\n      const strippedAdapter = new ApiGatewayV1Adapter({ stripBasePath });\n\n      const event = createApiGatewayV1(method, path, body);\n      const result = strippedAdapter.getRequest(event);\n\n      const remoteAddress = event.requestContext.identity.sourceIp;\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).not.toBeInstanceOf(Buffer);\n      expect(result.body).toBeUndefined();\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path.replace('/prod', ''),\n        event.queryStringParameters,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n  });\n\n  describe('getResponse', () => {\n    it('should return the correct mapping for the response', () => {\n      const method = 'PUT';\n      const path = '/events';\n      const requestBody = { name: 'H4ad Event' };\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createApiGatewayV1(method, path, requestBody);\n      const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n      const result = adapter.getResponse({\n        event,\n        log: {} as ILogger,\n        body: resultBody,\n        isBase64Encoded: resultIsBase64Encoded,\n        statusCode: resultStatusCode,\n        headers: resultHeaders,\n      });\n\n      const responseHeaders = getMultiValueHeadersMap(resultHeaders);\n\n      expect(result).toHaveProperty('statusCode', 200);\n      expect(result).toHaveProperty('body', resultBody);\n      expect(result).not.toHaveProperty('headers');\n      expect(result).toHaveProperty('multiValueHeaders', responseHeaders);\n      expect(result).toHaveProperty('isBase64Encoded', resultIsBase64Encoded);\n    });\n\n    it('should throw an error when framework send transfer-encoding=chunked in headers', () => {\n      const method = 'GET';\n      const path = '/events/stream';\n      const requestBody = undefined;\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createApiGatewayV1(method, path, requestBody);\n      const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n      resultHeaders['transfer-encoding'] = 'gzip,chunked';\n\n      expect(() =>\n        adapter.getResponse({\n          event,\n          log: {} as ILogger,\n          body: resultBody,\n          isBase64Encoded: resultIsBase64Encoded,\n          statusCode: resultStatusCode,\n          headers: resultHeaders,\n        }),\n      ).toThrowError('is not supported');\n    });\n\n    it('should throw an error when framework send chunkedEncoding=true in response', () => {\n      const method = 'GET';\n      const path = '/events/stream';\n      const requestBody = undefined;\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createApiGatewayV1(method, path, requestBody);\n      const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n      const fakeChunkedResponse = new ServerlessResponse({ method });\n\n      fakeChunkedResponse.chunkedEncoding = true;\n\n      expect(() =>\n        adapter.getResponse({\n          event,\n          log: {} as ILogger,\n          body: resultBody,\n          isBase64Encoded: resultIsBase64Encoded,\n          statusCode: resultStatusCode,\n          headers: resultHeaders,\n          response: fakeChunkedResponse,\n        }),\n      ).toThrowError('is not supported');\n    });\n\n    describe('when throwOnChunkedTransferEncoding=false', () => {\n      it('should NOT throw an error when framework send chunkedEncoding=true in response', () => {\n        const customAdapter = new ApiGatewayV1Adapter({\n          throwOnChunkedTransferEncoding: false,\n        });\n\n        const method = 'GET';\n        const path = '/events/stream';\n        const requestBody = undefined;\n\n        const resultBody = '{\"success\":true}';\n        const resultStatusCode = 200;\n        const resultIsBase64Encoded = false;\n\n        const event = createApiGatewayV1(method, path, requestBody);\n        const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n        const fakeChunkedResponse = new ServerlessResponse({ method });\n\n        fakeChunkedResponse.chunkedEncoding = true;\n\n        const result = customAdapter.getResponse({\n          event,\n          log: {} as ILogger,\n          body: resultBody,\n          isBase64Encoded: resultIsBase64Encoded,\n          statusCode: resultStatusCode,\n          headers: resultHeaders,\n          response: fakeChunkedResponse,\n        });\n\n        expect(result.multiValueHeaders!['transfer-encoding']).toBeUndefined();\n      });\n\n      it('should NOT throw an error when framework send transfer-encoding=chunked in headers', () => {\n        const customAdapter = new ApiGatewayV1Adapter({\n          throwOnChunkedTransferEncoding: false,\n        });\n\n        const method = 'GET';\n        const path = '/events/stream';\n        const requestBody = undefined;\n\n        const resultBody = '{\"success\":true}';\n        const resultStatusCode = 200;\n        const resultIsBase64Encoded = false;\n\n        const event = createApiGatewayV1(method, path, requestBody);\n        const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n        resultHeaders['transfer-encoding'] = 'gzip,chunked';\n\n        const result = customAdapter.getResponse({\n          event,\n          log: {} as ILogger,\n          body: resultBody,\n          isBase64Encoded: resultIsBase64Encoded,\n          statusCode: resultStatusCode,\n          headers: resultHeaders,\n        });\n\n        expect(result.multiValueHeaders!['transfer-encoding']).toBeUndefined();\n      });\n    });\n  });\n\n  describe('onErrorWhileForwarding', () => {\n    it('should resolver call succeed', () => {\n      const method = 'GET';\n      const path = '/events';\n      const requestBody = undefined;\n\n      const event = createApiGatewayV1(method, path, requestBody);\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<APIGatewayProxyResult> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = true;\n      const error = new Error('Test error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: APIGatewayProxyResult | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<APIGatewayProxyEvent>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).toBe(error.stack);\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n\n    it('should resolver call succeed but without sending errors', () => {\n      const method = 'GET';\n      const path = '/users';\n      const requestBody = undefined;\n\n      const event = createApiGatewayV1(method, path, requestBody);\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<APIGatewayProxyResult> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = false;\n      const error = new Error('Test error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: APIGatewayProxyResult | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<APIGatewayProxyEvent>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).toBe('');\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/aws/api-gateway-v2.adapter.spec.ts",
    "content": "import type { APIGatewayProxyEventV2 } from 'aws-lambda';\nimport type { APIGatewayProxyStructuredResultV2 } from 'aws-lambda/trigger/api-gateway-proxy';\nimport { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport {\n  type DelegatedResolver,\n  type GetResponseAdapterProps,\n  type ILogger,\n  ServerlessResponse,\n  getEventBodyAsBuffer,\n  getFlattenedHeadersMap,\n  getMultiValueHeadersMap,\n  getPathWithQueryStringParams,\n} from '../../../src';\nimport { ApiGatewayV2Adapter } from '../../../src/adapters/aws';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport { createApiGatewayV2 } from './utils/api-gateway-v2';\n\ndescribe(ApiGatewayV2Adapter.name, () => {\n  let adapter!: ApiGatewayV2Adapter;\n\n  beforeEach(() => {\n    adapter = new ApiGatewayV2Adapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(ApiGatewayV2Adapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(() => new ApiGatewayV2Adapter(), undefined);\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const method = 'PUT';\n      const path = '/collaborators';\n      const body = { name: 'H4ad Collaborator' };\n      const queryParams = { page: '2' };\n      const cookies = ['batata', 'joga10'];\n\n      const event = createApiGatewayV2(\n        method,\n        path,\n        body,\n        {},\n        queryParams,\n        cookies,\n      );\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.requestContext.http.sourceIp;\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).toBeInstanceOf(Buffer);\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(body),\n        false,\n      );\n      expect(result.body).toStrictEqual(bodyBuffer);\n      expect(result.headers).toHaveProperty('content-length');\n      expect(result.headers['content-length']).toBe(String(contentLength));\n\n      expect(result.headers['cookie']).toBe(cookies.join('; '));\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path,\n        event.rawQueryString,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n\n    it('should return the correct mapping for the request when it has no body', () => {\n      const method = 'GET';\n      const path = '/collaborators';\n      const body = undefined;\n\n      const event = createApiGatewayV2(method, path, body, {}, { page: '2' });\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.requestContext.http.sourceIp;\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n      expect(result.headers).not.toHaveProperty('cookie');\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).not.toBeInstanceOf(Buffer);\n      expect(result.body).toBeUndefined();\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path,\n        event.queryStringParameters,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n\n    it('should return the correct mapping for the request when send stripBasePath', () => {\n      const stripBasePath = '/prod';\n\n      const method = 'GET';\n      const path = '/prod/collaborators';\n      const body = undefined;\n\n      const strippedAdapter = new ApiGatewayV2Adapter({ stripBasePath });\n\n      const event = createApiGatewayV2(method, path, body);\n      const result = strippedAdapter.getRequest(event);\n\n      const remoteAddress = event.requestContext.http.sourceIp;\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).not.toBeInstanceOf(Buffer);\n      expect(result.body).toBeUndefined();\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path.replace('/prod', ''),\n        event.queryStringParameters,\n      );\n      expect(result.path).toBe(resultPath);\n    });\n  });\n\n  describe('getResponse', () => {\n    it('should return the correct mapping for the response', () => {\n      const method = 'PUT';\n      const path = '/collaborators';\n      const requestBody = { name: 'H4ad Collaborator V2' };\n      const queryParams = { page: '2' };\n      const cookies = ['batata', 'joga10'];\n      const resultCookies = 'batata; joga10';\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createApiGatewayV2(\n        method,\n        path,\n        requestBody,\n        {},\n        queryParams,\n        cookies,\n      );\n      const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n      const result = adapter.getResponse({\n        event,\n        log: {} as ILogger,\n        body: resultBody,\n        isBase64Encoded: resultIsBase64Encoded,\n        statusCode: resultStatusCode,\n        headers: {\n          ...resultHeaders,\n          'set-cookie': resultCookies,\n        },\n      });\n\n      expect(result).toHaveProperty('statusCode', 200);\n      expect(result).toHaveProperty('body', resultBody);\n      expect(result).toHaveProperty('headers');\n      expect(result.headers).not.toHaveProperty('set-cookie');\n      expect(result).toHaveProperty('cookies', [resultCookies]);\n      expect(result).toHaveProperty('isBase64Encoded', resultIsBase64Encoded);\n    });\n\n    it('should return the correct mapping for the response when set-cookie is array', () => {\n      const method = 'PUT';\n      const path = '/collaborators';\n      const requestBody = { name: 'H4ad Collaborator V2' };\n      const queryParams = { page: '2' };\n      const cookies = ['batata', 'joga10'];\n      const resultCookies = ['batata', 'joga10'];\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createApiGatewayV2(\n        method,\n        path,\n        requestBody,\n        {},\n        queryParams,\n        cookies,\n      );\n      const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n      const result = adapter.getResponse({\n        event,\n        log: {} as ILogger,\n        body: resultBody,\n        isBase64Encoded: resultIsBase64Encoded,\n        statusCode: resultStatusCode,\n        headers: {\n          ...resultHeaders,\n          'set-cookie': resultCookies,\n        },\n      });\n\n      expect(result).toHaveProperty('statusCode', 200);\n      expect(result).toHaveProperty('body', resultBody);\n      expect(result).toHaveProperty('headers');\n      expect(result.headers).not.toHaveProperty('set-cookie');\n      expect(result).toHaveProperty('cookies', resultCookies);\n      expect(result).toHaveProperty('isBase64Encoded', resultIsBase64Encoded);\n    });\n\n    it('should throw an error when framework send transfer-encoding=chunked in headers', () => {\n      const method = 'GET';\n      const path = '/collaborators/stream';\n      const requestBody = undefined;\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createApiGatewayV2(method, path, requestBody);\n      const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n      resultHeaders['transfer-encoding'] = 'gzip,chunked';\n\n      expect(() =>\n        adapter.getResponse({\n          event,\n          log: {} as ILogger,\n          body: resultBody,\n          isBase64Encoded: resultIsBase64Encoded,\n          statusCode: resultStatusCode,\n          headers: resultHeaders,\n        }),\n      ).toThrowError('is not supported');\n\n      const resultMultiValueHeaders = getMultiValueHeadersMap(event.headers);\n\n      resultMultiValueHeaders['transfer-encoding'] = ['gzip', 'chunked'];\n\n      expect(() =>\n        adapter.getResponse({\n          event,\n          log: {} as ILogger,\n          body: resultBody,\n          isBase64Encoded: resultIsBase64Encoded,\n          statusCode: resultStatusCode,\n          headers: resultMultiValueHeaders,\n        }),\n      ).toThrowError('is not supported');\n    });\n\n    it('should throw an error when framework send chunkedEncoding=true in response', () => {\n      const method = 'GET';\n      const path = '/collaborators/stream';\n      const requestBody = undefined;\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createApiGatewayV2(method, path, requestBody);\n      const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n      const fakeChunkedResponse = new ServerlessResponse({ method });\n\n      fakeChunkedResponse.chunkedEncoding = true;\n\n      expect(() =>\n        adapter.getResponse({\n          event,\n          log: {} as ILogger,\n          body: resultBody,\n          isBase64Encoded: resultIsBase64Encoded,\n          statusCode: resultStatusCode,\n          headers: resultHeaders,\n          response: fakeChunkedResponse,\n        }),\n      ).toThrowError('is not supported');\n    });\n\n    describe('when throwOnChunkedTransferEncoding=false', () => {\n      it('should NOT throw an error when framework send transfer-encoding=chunked in headers', () => {\n        const customAdapter = new ApiGatewayV2Adapter({\n          throwOnChunkedTransferEncoding: false,\n        });\n\n        const method = 'GET';\n        const path = '/collaborators/stream';\n        const requestBody = undefined;\n\n        const resultBody = '{\"success\":true}';\n        const resultStatusCode = 200;\n        const resultIsBase64Encoded = false;\n\n        const event = createApiGatewayV2(method, path, requestBody);\n        const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n        resultHeaders['transfer-encoding'] = 'gzip,chunked';\n\n        const result1 = customAdapter.getResponse({\n          event,\n          log: {} as ILogger,\n          body: resultBody,\n          isBase64Encoded: resultIsBase64Encoded,\n          statusCode: resultStatusCode,\n          headers: resultHeaders,\n        });\n\n        expect(result1.headers!['transfer-encoding']).toBeUndefined();\n\n        const resultMultiValueHeaders = getMultiValueHeadersMap(event.headers);\n\n        resultMultiValueHeaders['transfer-encoding'] = ['gzip', 'chunked'];\n\n        const result2 = customAdapter.getResponse({\n          event,\n          log: {} as ILogger,\n          body: resultBody,\n          isBase64Encoded: resultIsBase64Encoded,\n          statusCode: resultStatusCode,\n          headers: resultMultiValueHeaders,\n        });\n\n        expect(result2.headers!['transfer-encoding']).toBeUndefined();\n      });\n\n      it('should NOT throw an error when framework send chunkedEncoding=true in response', () => {\n        const customAdapter = new ApiGatewayV2Adapter({\n          throwOnChunkedTransferEncoding: false,\n        });\n\n        const method = 'GET';\n        const path = '/collaborators/stream';\n        const requestBody = undefined;\n\n        const resultBody = '{\"success\":true}';\n        const resultStatusCode = 200;\n        const resultIsBase64Encoded = false;\n\n        const event = createApiGatewayV2(method, path, requestBody);\n        const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n        const fakeChunkedResponse = new ServerlessResponse({ method });\n\n        fakeChunkedResponse.chunkedEncoding = true;\n\n        const result = customAdapter.getResponse({\n          event,\n          log: {} as ILogger,\n          body: resultBody,\n          isBase64Encoded: resultIsBase64Encoded,\n          statusCode: resultStatusCode,\n          headers: resultHeaders,\n          response: fakeChunkedResponse,\n        });\n\n        expect(result.headers!['transfer-encoding']).toBeUndefined();\n      });\n    });\n  });\n\n  describe('onErrorWhileForwarding', () => {\n    it('should resolver call succeed', () => {\n      const method = 'GET';\n      const path = '/events';\n      const requestBody = undefined;\n\n      const event = createApiGatewayV2(method, path, requestBody);\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<APIGatewayProxyStructuredResultV2> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = true;\n      const error = new Error('Test error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: APIGatewayProxyStructuredResultV2 | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<APIGatewayProxyEventV2>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).toBe(error.stack);\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n\n    it('should resolver call succeed but without sending errors', () => {\n      const method = 'GET';\n      const path = '/users';\n      const requestBody = undefined;\n\n      const event = createApiGatewayV2(method, path, requestBody);\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<APIGatewayProxyStructuredResultV2> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = false;\n      const error = new Error('Test error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: APIGatewayProxyStructuredResultV2 | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<APIGatewayProxyEventV2>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).toBe('');\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/aws/aws-simple-adapter.spec.ts",
    "content": "import { describe, expect, it, vitest } from 'vitest';\nimport {\n  type DelegatedResolver,\n  EmptyResponse,\n  type ILogger,\n  createDefaultLogger,\n  getEventBodyAsBuffer,\n} from '../../../src';\nimport { AwsSimpleAdapter } from '../../../src/adapters/aws';\nimport { createDynamoDBEvent } from './utils/dynamodb';\nimport { createSNSEvent } from './utils/sns';\nimport { createSQSEvent } from './utils/sqs';\n\nconst sampleEvents = [\n  createSQSEvent(),\n  createSNSEvent(),\n  createDynamoDBEvent(),\n];\n\nclass TestAdapter extends AwsSimpleAdapter<any> {}\n\ndescribe(AwsSimpleAdapter.name, () => {\n  describe('getAdapterName', () => {\n    it('should throw not implemented error', () => {\n      const adapter = new TestAdapter({\n        forwardPath: '/test',\n        forwardMethod: 'POST',\n        host: 'test.com.com',\n      });\n\n      expect(() => adapter.getAdapterName()).toThrow('not implemented');\n    });\n  });\n\n  describe('canHandle', () => {\n    it('should throw not implemented error', () => {\n      const adapter = new TestAdapter({\n        forwardPath: '/test',\n        forwardMethod: 'POST',\n        host: 'test.com.com',\n      });\n\n      expect(() => adapter.canHandle(null)).toThrow('not implemented');\n    });\n  });\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      for (const event of sampleEvents) {\n        const adapter = new TestAdapter({\n          forwardPath: '/test',\n          forwardMethod: 'POST',\n          host: 'test.amazonaws.com',\n          batch: false,\n        });\n\n        const result = adapter.getRequest(event);\n\n        expect(result.method).toBe('POST');\n        expect(result.path).toBe('/test');\n        expect(result.headers).toHaveProperty('host', 'test.amazonaws.com');\n        expect(result.headers).toHaveProperty(\n          'content-type',\n          'application/json',\n        );\n\n        const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n          JSON.stringify(event),\n          false,\n        );\n\n        expect(result.body).toBeInstanceOf(Buffer);\n        expect(result.body).toStrictEqual(bodyBuffer);\n\n        expect(result.headers).toHaveProperty(\n          'content-length',\n          String(contentLength),\n        );\n      }\n    });\n\n    it('should return the correct mapping for the request with custom path and method', () => {\n      const event = createSQSEvent();\n\n      const method = 'PUT';\n      const path = '/custom/test';\n\n      const customAdapter = new TestAdapter({\n        forwardMethod: method,\n        forwardPath: path,\n        host: 'test.amazonaws.com',\n      });\n\n      const result = customAdapter.getRequest(event);\n\n      expect(result.method).toBe(method);\n      expect(result.path).toBe(path);\n      expect(result.headers).toHaveProperty('host', 'test.amazonaws.com');\n      expect(result.headers).toHaveProperty('content-type', 'application/json');\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(event),\n        false,\n      );\n\n      expect(result.body).toBeInstanceOf(Buffer);\n      expect(result.body).toStrictEqual(bodyBuffer);\n\n      expect(result.headers).toHaveProperty(\n        'content-length',\n        String(contentLength),\n      );\n    });\n  });\n\n  describe('getResponse', () => {\n    it('should throw for invalid status', () => {\n      const options: [status: number, error: boolean][] = [\n        [101, true],\n        [200, false],\n        [204, false],\n        [301, false],\n        [303, false],\n        [400, true],\n        [401, true],\n        [404, true],\n        [500, true],\n        [503, true],\n      ];\n\n      const adapter = new TestAdapter({\n        forwardPath: '/test',\n        forwardMethod: 'POST',\n        host: 'test.amazonaws.com',\n        batch: false,\n      });\n\n      for (const [status, shouldThrowError] of options) {\n        if (shouldThrowError) {\n          expect(() =>\n            adapter.getResponse({\n              event: null,\n              body: JSON.stringify({ ok: true }),\n              log: createDefaultLogger(),\n              headers: {},\n              statusCode: status,\n              isBase64Encoded: false,\n            }),\n          ).toThrowError(`\"statusCode\":${status}`);\n        } else {\n          expect(() =>\n            adapter.getResponse({\n              event: null,\n              body: JSON.stringify({ ok: true }),\n              log: createDefaultLogger(),\n              headers: {},\n              statusCode: status,\n              isBase64Encoded: false,\n            }),\n          ).not.toThrowError(`\"statusCode\":${status}`);\n        }\n      }\n    });\n\n    describe('batch: false', () => {\n      it('should not throw when body is base64', () => {\n        const adapter = new TestAdapter({\n          forwardPath: '/test',\n          forwardMethod: 'POST',\n          host: 'test.amazonaws.com',\n          batch: false,\n        });\n\n        expect(() =>\n          adapter.getResponse({\n            event: null,\n            body: JSON.stringify({ ok: true }),\n            log: createDefaultLogger(),\n            headers: {},\n            statusCode: 200,\n            isBase64Encoded: true,\n          }),\n        ).not.toThrowError('could not be base64 encoded');\n      });\n\n      it('should return the correct mapping for the response', () => {\n        const adapter = new TestAdapter({\n          forwardPath: '/test',\n          forwardMethod: 'POST',\n          host: 'test.amazonaws.com',\n          batch: false,\n        });\n\n        const result = adapter.getResponse({\n          event: null,\n          body: JSON.stringify({ ok: true }),\n          log: createDefaultLogger(),\n          headers: {},\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(result).toBe(EmptyResponse);\n      });\n    });\n  });\n\n  describe('batch: true', () => {\n    it('should throw when body is base64', () => {\n      const adapter = new TestAdapter({\n        forwardPath: '/test',\n        forwardMethod: 'POST',\n        host: 'test.amazonaws.com',\n        batch: true,\n      });\n\n      expect(() =>\n        adapter.getResponse({\n          event: null,\n          body: JSON.stringify({ ok: true }),\n          log: createDefaultLogger(),\n          headers: {},\n          statusCode: 200,\n          isBase64Encoded: true,\n        }),\n      ).toThrowError('could not be base64 encoded');\n    });\n\n    it('should return the body when response is correct', () => {\n      const adapter = new TestAdapter({\n        forwardPath: '/test',\n        forwardMethod: 'POST',\n        host: 'test.amazonaws.com',\n        batch: true,\n      });\n\n      const body = { ok: true };\n\n      const response = adapter.getResponse({\n        event: null,\n        body: JSON.stringify(body),\n        log: createDefaultLogger(),\n        headers: {},\n        statusCode: 200,\n        isBase64Encoded: false,\n      });\n\n      expect(response).toStrictEqual(body);\n    });\n\n    it('should return empty when body is also empty', () => {\n      const adapter = new TestAdapter({\n        forwardPath: '/test',\n        forwardMethod: 'POST',\n        host: 'test.amazonaws.com',\n        batch: true,\n      });\n\n      const body = '';\n\n      const response = adapter.getResponse({\n        event: null,\n        body,\n        log: createDefaultLogger(),\n        headers: {},\n        statusCode: 200,\n        isBase64Encoded: false,\n      });\n\n      expect(response).toStrictEqual(EmptyResponse);\n    });\n  });\n\n  describe('onErrorWhileForwarding', () => {\n    it('should resolver just call fail without get response', () => {\n      const adapter = new TestAdapter({\n        forwardPath: '/test',\n        forwardMethod: 'POST',\n        host: 'test.amazonaws.com',\n        batch: true,\n      });\n\n      const error = new Error('fail because I need to test.');\n      const resolver: DelegatedResolver<any> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      adapter.getResponse = vitest.fn();\n      adapter.onErrorWhileForwarding({\n        event: {},\n        error,\n        delegatedResolver: resolver,\n        log: {} as ILogger,\n        respondWithErrors: false,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(0);\n\n      expect(resolver.fail).toHaveBeenCalledWith(error);\n      expect(resolver.succeed).toHaveBeenCalledTimes(0);\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/aws/dynamodb.adapter.spec.ts",
    "content": "import { beforeEach, describe, expect, it } from 'vitest';\nimport { getEventBodyAsBuffer } from '../../../src';\nimport { DynamoDBAdapter } from '../../../src/adapters/aws';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport { createDynamoDBEvent } from './utils/dynamodb';\n\ndescribe(DynamoDBAdapter.name, () => {\n  let adapter!: DynamoDBAdapter;\n\n  beforeEach(() => {\n    adapter = new DynamoDBAdapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(DynamoDBAdapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(() => new DynamoDBAdapter(), undefined);\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const event = createDynamoDBEvent();\n\n      const result = adapter.getRequest(event);\n\n      expect(result.method).toBe('POST');\n      expect(result.path).toBe('/dynamo');\n      expect(result.headers).toHaveProperty('host', 'dynamodb.amazonaws.com');\n      expect(result.headers).toHaveProperty('content-type', 'application/json');\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(event),\n        false,\n      );\n\n      expect(result.body).toBeInstanceOf(Buffer);\n      expect(result.body).toStrictEqual(bodyBuffer);\n\n      expect(result.headers).toHaveProperty(\n        'content-length',\n        String(contentLength),\n      );\n    });\n\n    it('should return the correct mapping for the request with custom path and method', () => {\n      const event = createDynamoDBEvent();\n\n      const method = 'PUT';\n      const path = '/custom/dynamo';\n\n      const customAdapter = new DynamoDBAdapter({\n        dynamoDBForwardMethod: method,\n        dynamoDBForwardPath: path,\n      });\n\n      const result = customAdapter.getRequest(event);\n\n      expect(result.method).toBe(method);\n      expect(result.path).toBe(path);\n      expect(result.headers).toHaveProperty('host', 'dynamodb.amazonaws.com');\n      expect(result.headers).toHaveProperty('content-type', 'application/json');\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(event),\n        false,\n      );\n\n      expect(result.body).toBeInstanceOf(Buffer);\n      expect(result.body).toStrictEqual(bodyBuffer);\n\n      expect(result.headers).toHaveProperty(\n        'content-length',\n        String(contentLength),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/aws/event-bridge.adapter.spec.ts",
    "content": "import { beforeEach, describe, expect, it } from 'vitest';\nimport { getEventBodyAsBuffer } from '../../../src';\nimport { EventBridgeAdapter } from '../../../src/adapters/aws';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport { createEventBridgeEvent } from './utils/event-bridge';\n\ndescribe(EventBridgeAdapter.name, () => {\n  let adapter!: EventBridgeAdapter;\n\n  beforeEach(() => {\n    adapter = new EventBridgeAdapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(EventBridgeAdapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(() => new EventBridgeAdapter(), undefined);\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const event = createEventBridgeEvent();\n\n      const result = adapter.getRequest(event);\n\n      expect(result.method).toBe('POST');\n      expect(result.path).toBe('/eventbridge');\n      expect(result.headers).toHaveProperty('host', 'events.amazonaws.com');\n      expect(result.headers).toHaveProperty('content-type', 'application/json');\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(event),\n        false,\n      );\n\n      expect(result.body).toBeInstanceOf(Buffer);\n      expect(result.body).toStrictEqual(bodyBuffer);\n\n      expect(result.headers).toHaveProperty(\n        'content-length',\n        String(contentLength),\n      );\n    });\n\n    it('should return the correct mapping for the request with custom path and method', () => {\n      const method = 'PUT';\n      const path = '/prod/eventbridge';\n\n      const customAdapter = new EventBridgeAdapter({\n        eventBridgeForwardMethod: method,\n        eventBridgeForwardPath: path,\n      });\n\n      const event = createEventBridgeEvent();\n\n      const result = customAdapter.getRequest(event);\n\n      expect(result.method).toBe(method);\n      expect(result.path).toBe(path);\n      expect(result.headers).toHaveProperty('host', 'events.amazonaws.com');\n      expect(result.headers).toHaveProperty('content-type', 'application/json');\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(event),\n        false,\n      );\n\n      expect(result.body).toBeInstanceOf(Buffer);\n      expect(result.body).toStrictEqual(bodyBuffer);\n\n      expect(result.headers).toHaveProperty(\n        'content-length',\n        String(contentLength),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/aws/lambda-edge.adapter.spec.ts",
    "content": "import { join } from 'path';\nimport type {\n  CloudFrontHeaders,\n  CloudFrontRequest,\n} from 'aws-lambda/common/cloudfront';\nimport type {\n  CloudFrontRequestEvent,\n  CloudFrontRequestResult,\n} from 'aws-lambda/trigger/cloudfront-request';\nimport { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport {\n  type BothValueHeaders,\n  type DelegatedResolver,\n  type ILogger,\n  type MultiValueHeaders,\n  type SingleValueHeaders,\n} from '../../../src';\nimport {\n  DEFAULT_LAMBDA_EDGE_DISALLOWED_HEADERS,\n  DEFAULT_ORIGIN_MAX_RESPONSE_SIZE_IN_BYTES,\n  DEFAULT_VIEWER_MAX_RESPONSE_SIZE_IN_BYTES,\n  LambdaEdgeAdapter,\n} from '../../../src/adapters/aws';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport {\n  createLambdaEdgeOriginEvent,\n  createLambdaEdgeViewerEvent,\n} from './utils/lambda-edge';\n\ndescribe(LambdaEdgeAdapter.name, () => {\n  let adapter!: LambdaEdgeAdapter;\n\n  beforeEach(() => {\n    adapter = new LambdaEdgeAdapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(LambdaEdgeAdapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(() => new LambdaEdgeAdapter(), undefined);\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const events: [\n        factory:\n          | typeof createLambdaEdgeOriginEvent\n          | typeof createLambdaEdgeViewerEvent,\n        method: string,\n        path: string,\n        body?: any,\n      ][] = [\n        [createLambdaEdgeOriginEvent, 'GET', '/image.png', undefined],\n        [\n          createLambdaEdgeOriginEvent,\n          'POST',\n          'batata.png',\n          {\n            base64: Buffer.from('batata', 'utf-8').toString('base64'),\n          },\n        ],\n        [createLambdaEdgeViewerEvent, 'GET', '/image4343.png', undefined],\n        [\n          createLambdaEdgeViewerEvent,\n          'PUT',\n          'banana.png',\n          {\n            base64: Buffer.from('batata', 'utf-8').toString('base64'),\n          },\n        ],\n      ];\n\n      for (const [createEvent, method, path, body] of events) {\n        const lambdaEdgeEvent = createEvent(method, path, body);\n        const cloudfrontRequest = lambdaEdgeEvent.Records[0].cf.request;\n\n        const result = adapter.getRequest(lambdaEdgeEvent);\n\n        const keys = Object.keys(result);\n        const expectedKeys = [\n          'method',\n          'path',\n          'headers',\n          'body',\n          'remoteAddress',\n          'host',\n          'hostname',\n        ];\n\n        expect(keys.length === expectedKeys.length).toBe(true);\n        expect(keys.every(key => expectedKeys.includes(key))).toBe(true);\n\n        expect(result.method).toBe(method);\n        expect(result.path).toBe(path);\n\n        const someHeaderValueIsArray = Object.values(result.headers).some(\n          Array.isArray,\n        );\n\n        expect(someHeaderValueIsArray).toBe(false);\n\n        const headerKeys = Object.keys(result.headers);\n        const expectedHeaderKeys = Object.keys(cloudfrontRequest.headers);\n\n        if (result.body) expectedHeaderKeys.push('content-length');\n\n        expect(headerKeys.length === expectedHeaderKeys.length).toBe(true);\n        expect(headerKeys.every(key => expectedHeaderKeys.includes(key))).toBe(\n          true,\n        );\n\n        if (result.body === undefined) expect(result.body).toBeUndefined();\n        else {\n          const dataAsBase64 = Buffer.from(\n            JSON.stringify(body),\n            'utf-8',\n          ).toString('base64');\n\n          const jsonString = JSON.stringify({\n            action: 'read-only',\n            encoding: 'base64',\n            inputTruncated: false,\n            data: dataAsBase64,\n          });\n\n          expect(result.body.toString('utf-8')).toBe(jsonString);\n        }\n\n        expect(result.remoteAddress).toBe(cloudfrontRequest.clientIp);\n\n        const host = cloudfrontRequest.headers['host'][0].value;\n\n        expect(result.host).toBe(host);\n        expect(result.hostname).toBe(host);\n      }\n    });\n\n    it('should return the correct mapping for the request with query params', () => {\n      const lambdaEvent = createLambdaEdgeOriginEvent(\n        'GET',\n        '/image_of_apple.png',\n        undefined,\n        undefined,\n        'pretty=true',\n      );\n\n      const result = adapter.getRequest(lambdaEvent);\n\n      expect(result.path).toBe('/image_of_apple.png?pretty=true');\n    });\n\n    it('should return the correct mapping for the request with custom path function', () => {\n      const lambdaEvent = createLambdaEdgeOriginEvent(\n        'GET',\n        '/image2.png',\n        undefined,\n        undefined,\n        'potato=true',\n      );\n\n      const customAdapter = new LambdaEdgeAdapter({\n        getPathFromEvent: event => join('/prod', event.cf.request.uri),\n      });\n\n      const result = customAdapter.getRequest(lambdaEvent);\n\n      expect(result.path).toBe('/prod/image2.png');\n\n      // certifies the behavior described in the comments of `getPathFromEvent`.\n      expect(result.path).not.toBe('/prod/image2.png?potato=true');\n    });\n  });\n\n  describe('getResponse', () => {\n    it('should return the correct mapping for the response', () => {\n      const options: CloudFrontRequestEvent[] = [\n        createLambdaEdgeOriginEvent('GET', '/potato.png'),\n        createLambdaEdgeViewerEvent('GET', '/apple.png'),\n      ];\n\n      for (const event of options) {\n        const cloudFrontRequest = event.Records[0].cf.request;\n        const body = JSON.stringify(cloudFrontRequest);\n\n        const result = adapter.getResponse({\n          event,\n          body,\n          headers: {},\n          log: {} as ILogger,\n          statusCode: 200,\n          isBase64Encoded: false,\n        }) as CloudFrontRequest;\n\n        expect(result).toBeDefined();\n\n        expect(result).toHaveProperty('headers');\n        expect(result.headers).toHaveProperty(\n          'host',\n          cloudFrontRequest.headers['host'],\n        );\n\n        expect(result).toHaveProperty('clientIp', cloudFrontRequest.clientIp);\n        expect(result).toHaveProperty('method', cloudFrontRequest.method);\n        expect(result.origin).toEqual(cloudFrontRequest.origin);\n        expect(result).toHaveProperty(\n          'querystring',\n          cloudFrontRequest.querystring,\n        );\n        expect(result).toHaveProperty('uri', cloudFrontRequest.uri);\n\n        expect(result).not.toHaveProperty('body');\n      }\n    });\n\n    it('should return the correct mapping for the response even if we reach the max response size', () => {\n      const bigResponseForOrigin = new Array(\n        DEFAULT_ORIGIN_MAX_RESPONSE_SIZE_IN_BYTES + 1,\n      ).map(() => 'a');\n      const bigResponseForView = new Array(\n        DEFAULT_VIEWER_MAX_RESPONSE_SIZE_IN_BYTES + 1,\n      ).map(() => 'b');\n\n      const options: CloudFrontRequestEvent[] = [\n        createLambdaEdgeOriginEvent('GET', '/potato.png', {\n          bigResponseForOrigin,\n        }),\n        createLambdaEdgeViewerEvent('GET', '/apple.png', {\n          bigResponseForView,\n        }),\n      ];\n\n      for (const event of options) {\n        const cloudFrontRequest = event.Records[0].cf.request;\n        const body = JSON.stringify(cloudFrontRequest);\n\n        const log = {\n          error: vitest.fn(message =>\n            expect(message).toContain('Max response size exceeded'),\n          ) as any,\n        } as ILogger;\n\n        adapter.getResponse({\n          event,\n          body,\n          headers: {},\n          log,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(log.error).toHaveBeenCalledTimes(1);\n      }\n    });\n\n    it('should return the correct mapping for the response with option \"shouldUseHeadersFromFramework\"', () => {\n      const event = createLambdaEdgeViewerEvent('GET', '/potato.png');\n      const cloudFrontRequest = event.Records[0].cf.request;\n      const body = JSON.stringify(cloudFrontRequest);\n\n      const customAdapter = new LambdaEdgeAdapter({\n        shouldUseHeadersFromFramework: true,\n      });\n\n      const options: BothValueHeaders[] = [\n        { batata: 'true' },\n        { batata: ['true'] },\n      ];\n\n      for (const headers of options) {\n        const result = customAdapter.getResponse({\n          event,\n          body,\n          headers,\n          log: {} as ILogger,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(result!.headers!['batata']).toStrictEqual([\n          { key: 'batata', value: 'true' },\n        ]);\n\n        expect(result!.headers!['batata']).not.toStrictEqual([\n          { key: 'batata', value: Math.random().toString() },\n        ]);\n      }\n    });\n\n    it('should return the correct mapping for the response with option \"disallowedHeaders\"', () => {\n      const disallowedHeadersList =\n        DEFAULT_LAMBDA_EDGE_DISALLOWED_HEADERS.filter(\n          header => typeof header === 'string',\n        ) as string[];\n\n      expect(disallowedHeadersList.length > 0).toBe(true);\n\n      const allDisallowedHeadersMap: SingleValueHeaders = {};\n      const allDisallowedMultiValueHeadersMap: MultiValueHeaders = {};\n      const allDisallowedCloudfrontHeaders: CloudFrontHeaders = {};\n\n      for (const header of disallowedHeadersList) {\n        allDisallowedHeadersMap[header] = Math.random().toString();\n        allDisallowedMultiValueHeadersMap[header] = [Math.random().toString()];\n        allDisallowedCloudfrontHeaders[header] = [\n          { key: header, value: Math.random().toString() },\n        ];\n      }\n\n      const options: [\n        adapter: LambdaEdgeAdapter,\n        event: CloudFrontRequestEvent,\n        headers: BothValueHeaders,\n      ][] = [\n        [\n          new LambdaEdgeAdapter({\n            disallowedHeaders: disallowedHeadersList,\n          }),\n          createLambdaEdgeViewerEvent(\n            'GET',\n            '/potato.png',\n            undefined,\n            allDisallowedCloudfrontHeaders,\n          ),\n          {},\n        ],\n        [\n          new LambdaEdgeAdapter({\n            disallowedHeaders: disallowedHeadersList,\n          }),\n          createLambdaEdgeOriginEvent(\n            'GET',\n            '/potato.png',\n            undefined,\n            allDisallowedCloudfrontHeaders,\n          ),\n          {},\n        ],\n        [\n          new LambdaEdgeAdapter({\n            shouldUseHeadersFromFramework: true,\n            disallowedHeaders: disallowedHeadersList,\n          }),\n          createLambdaEdgeViewerEvent('GET', '/potato.png'),\n          allDisallowedHeadersMap,\n        ],\n        [\n          new LambdaEdgeAdapter({\n            shouldUseHeadersFromFramework: true,\n            disallowedHeaders: disallowedHeadersList,\n          }),\n          createLambdaEdgeViewerEvent('GET', '/apple.png'),\n          allDisallowedMultiValueHeadersMap,\n        ],\n        [\n          new LambdaEdgeAdapter({\n            shouldUseHeadersFromFramework: true,\n            disallowedHeaders: disallowedHeadersList,\n          }),\n          createLambdaEdgeOriginEvent('GET', '/apple.png'),\n          allDisallowedHeadersMap,\n        ],\n        [\n          new LambdaEdgeAdapter({\n            shouldUseHeadersFromFramework: true,\n            disallowedHeaders: disallowedHeadersList,\n          }),\n          createLambdaEdgeOriginEvent('GET', '/apple.png'),\n          allDisallowedMultiValueHeadersMap,\n        ],\n      ];\n\n      for (const [customAdapter, event, headers] of options) {\n        const cloudFrontRequest = event.Records[0].cf.request;\n        const body = JSON.stringify(cloudFrontRequest);\n\n        const result = customAdapter.getResponse({\n          event,\n          body,\n          headers,\n          log: {} as ILogger,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(Object.keys(result!.headers!)).toHaveLength(0);\n      }\n    });\n\n    it('should return the correct mapping for the response with option \"shouldStripHeader\"', () => {\n      const customAdapter = new LambdaEdgeAdapter({\n        shouldStripHeader: () => true,\n      });\n\n      const options: CloudFrontRequestEvent[] = [\n        createLambdaEdgeViewerEvent('GET', '/potato.png'),\n        createLambdaEdgeOriginEvent('GET', '/apple.png'),\n      ];\n\n      for (const event of options) {\n        const cloudFrontRequest = event.Records[0].cf.request;\n        const body = JSON.stringify(cloudFrontRequest);\n\n        const result = customAdapter.getResponse({\n          event,\n          body,\n          headers: {},\n          log: {} as ILogger,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(Object.keys(result!.headers!)).toHaveLength(0);\n      }\n    });\n\n    it('should return the correct mapping for the response with option \"onResponseSizeExceedLimit\"', () => {\n      const customAdapter = new LambdaEdgeAdapter({\n        originMaxResponseSizeInBytes: 0,\n        viewerMaxResponseSizeInBytes: 0,\n      });\n\n      const options: CloudFrontRequestEvent[] = [\n        createLambdaEdgeViewerEvent('GET', '/potato.png', { potato: true }),\n        createLambdaEdgeOriginEvent('GET', '/apple.png', { apple: true }),\n      ];\n\n      for (const event of options) {\n        const cloudFrontRequest = event.Records[0].cf.request;\n        const body = JSON.stringify(cloudFrontRequest);\n\n        const log = {\n          error: vitest.fn(message =>\n            expect(message).toContain('Max response size exceeded'),\n          ) as any,\n        } as ILogger;\n\n        const result = customAdapter.getResponse({\n          event,\n          body,\n          headers: {},\n          log,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(result).toBeDefined();\n        expect(log.error).toHaveBeenCalledTimes(1);\n\n        const onResponseSizeExceedLimit = vitest.fn();\n\n        const customAdapter2 = new LambdaEdgeAdapter({\n          originMaxResponseSizeInBytes: 0,\n          viewerMaxResponseSizeInBytes: 0,\n          onResponseSizeExceedLimit,\n        });\n\n        customAdapter2.getResponse({\n          event,\n          body,\n          headers: {},\n          log: {} as ILogger,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(onResponseSizeExceedLimit).toHaveBeenCalled();\n      }\n    });\n  });\n\n  describe('onErrorWhileForwarding', () => {\n    it('should resolver call succeed', () => {\n      const options: [\n        event: CloudFrontRequestEvent,\n        respondWithError: boolean,\n      ][] = [\n        [\n          createLambdaEdgeViewerEvent('GET', '/potato.png', { potato: true }),\n          false,\n        ],\n        [\n          createLambdaEdgeOriginEvent('GET', '/apple.png', { apple: true }),\n          false,\n        ],\n        [createLambdaEdgeViewerEvent('GET', '/mapple.png'), true],\n        [createLambdaEdgeOriginEvent('GET', '/juice.png'), true],\n      ];\n\n      for (const [event, respondWithErrors] of options) {\n        const log = {} as ILogger;\n\n        const resolver: DelegatedResolver<CloudFrontRequestResult> = {\n          fail: vitest.fn(),\n          succeed: vitest.fn(),\n        };\n\n        const error = new Error('Test error');\n\n        adapter.onErrorWhileForwarding({\n          event,\n          log,\n          delegatedResolver: resolver,\n          respondWithErrors,\n          error,\n        });\n\n        expect(resolver.fail).toHaveBeenCalledTimes(1);\n        expect(resolver.succeed).toHaveBeenCalledTimes(0);\n      }\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/aws/request-lambda-edge.adapter.spec.ts",
    "content": "import type { CloudFrontHeaders } from 'aws-lambda/common/cloudfront';\nimport type {\n  CloudFrontRequestEvent,\n  CloudFrontRequestResult,\n} from 'aws-lambda/trigger/cloudfront-request';\nimport { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport {\n  type BothValueHeaders,\n  type DelegatedResolver,\n  type ILogger,\n  type MultiValueHeaders,\n  type SingleValueHeaders,\n} from '../../../src';\nimport {\n  DEFAULT_LAMBDA_EDGE_DISALLOWED_HEADERS,\n  DEFAULT_ORIGIN_MAX_RESPONSE_SIZE_IN_BYTES,\n  DEFAULT_VIEWER_MAX_RESPONSE_SIZE_IN_BYTES,\n  RequestLambdaEdgeAdapter,\n} from '../../../src/adapters/aws';\nimport {\n  createLambdaEdgeOriginEvent,\n  createLambdaEdgeViewerEvent,\n} from './utils/lambda-edge';\n\ndescribe(RequestLambdaEdgeAdapter.name, () => {\n  let adapter!: RequestLambdaEdgeAdapter;\n\n  beforeEach(() => {\n    adapter = new RequestLambdaEdgeAdapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(RequestLambdaEdgeAdapter.name);\n    });\n  });\n\n  describe('canHandle', () => {\n    it('should handle origin-request and viewer-request', () => {\n      expect(\n        adapter.canHandle(createLambdaEdgeViewerEvent('GET', '/users')),\n      ).toBe(true);\n\n      expect(\n        adapter.canHandle(createLambdaEdgeOriginEvent('GET', '/users')),\n      ).toBe(true);\n\n      expect(adapter.canHandle({})).toBe(false);\n    });\n  });\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const events: [\n        factory:\n          | typeof createLambdaEdgeOriginEvent\n          | typeof createLambdaEdgeViewerEvent,\n        method: string,\n        path: string,\n        body?: any,\n        headers?: CloudFrontHeaders,\n      ][] = [\n        [createLambdaEdgeOriginEvent, 'GET', '/projects', undefined],\n        [\n          createLambdaEdgeOriginEvent,\n          'GET',\n          '/users',\n          undefined,\n          {\n            test: [{ key: 'test', value: '1' }],\n            test2: [\n              { key: 'Test2', value: '1' },\n              { key: 'Test2', value: '2' },\n            ],\n          },\n        ],\n        [\n          createLambdaEdgeOriginEvent,\n          'POST',\n          'batata.png',\n          {\n            base64: Buffer.from('batata', 'utf-8').toString('base64'),\n          },\n        ],\n        [createLambdaEdgeViewerEvent, 'GET', '/products', undefined],\n        [\n          createLambdaEdgeViewerEvent,\n          'PUT',\n          '/tests',\n          {\n            base64: Buffer.from('batata', 'utf-8').toString('base64'),\n          },\n        ],\n      ];\n\n      for (const [createEvent, method, path, body, headers] of events) {\n        const lambdaEdgeEvent = createEvent(method, path, body, headers);\n        const cloudfrontRequest = lambdaEdgeEvent.Records[0].cf.request;\n\n        const result = adapter.getRequest(lambdaEdgeEvent);\n\n        const keys = Object.keys(result);\n        const expectedKeys = [\n          'method',\n          'path',\n          'headers',\n          'body',\n          'remoteAddress',\n          'host',\n          'hostname',\n        ];\n\n        expect(keys.length === expectedKeys.length).toBe(true);\n        expect(keys.every(key => expectedKeys.includes(key))).toBe(true);\n\n        expect(result.method).toBe(method);\n        expect(result.path).toBe(path);\n\n        const someHeaderValueIsArray = Object.values(result.headers).some(\n          Array.isArray,\n        );\n\n        expect(someHeaderValueIsArray).toBe(false);\n\n        const headerKeys = Object.keys(result.headers);\n        const expectedHeaderKeys = Object.keys(cloudfrontRequest.headers);\n\n        if (result.body) expectedHeaderKeys.push('content-length');\n\n        expect(headerKeys.length === expectedHeaderKeys.length).toBe(true);\n        expect(headerKeys.every(key => expectedHeaderKeys.includes(key))).toBe(\n          true,\n        );\n\n        if (result.body === undefined) expect(result.body).toBeUndefined();\n        else expect(result.body.toString('utf-8')).toBe(JSON.stringify(body));\n\n        expect(result.remoteAddress).toBe(cloudfrontRequest.clientIp);\n\n        if (cloudfrontRequest.headers['host']) {\n          const host = cloudfrontRequest.headers['host'][0].value;\n\n          expect(result.host).toBe(host);\n          expect(result.hostname).toBe(host);\n        } else {\n          expect(result.host).toBeUndefined();\n          expect(result.hostname).toBeUndefined();\n        }\n      }\n    });\n\n    it('should return the correct mapping for the request with query params', () => {\n      const lambdaEvent = createLambdaEdgeOriginEvent(\n        'GET',\n        '/image_of_apple.png',\n        undefined,\n        undefined,\n        'pretty=true',\n      );\n\n      const result = adapter.getRequest(lambdaEvent);\n\n      expect(result.path).toBe('/image_of_apple.png?pretty=true');\n    });\n\n    it('should return the correct path for the request with stripBasePath', () => {\n      const lambdaEvent = createLambdaEdgeOriginEvent(\n        'GET',\n        '/api/users',\n        undefined,\n        undefined,\n        'potato=true',\n      );\n\n      const customAdapter = new RequestLambdaEdgeAdapter({\n        stripBasePath: '/api',\n      });\n\n      const result = customAdapter.getRequest(lambdaEvent);\n\n      expect(result.path).toBe('/users?potato=true');\n    });\n  });\n\n  describe('getResponse', () => {\n    it('should return the correct mapping for the response', () => {\n      const options: CloudFrontRequestEvent[] = [\n        createLambdaEdgeOriginEvent('GET', '/users'),\n        createLambdaEdgeViewerEvent('GET', '/products'),\n      ];\n\n      for (const event of options) {\n        const cloudFrontRequest = event.Records[0].cf.request;\n        const body = JSON.stringify(cloudFrontRequest);\n\n        const result = adapter.getResponse({\n          event,\n          body,\n          headers: {\n            Test: 'value',\n          },\n          log: {} as ILogger,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(result).toBeDefined();\n        expect(result.headers).toEqual({\n          test: [{ key: 'Test', value: 'value' }],\n        });\n        expect(result.bodyEncoding).toEqual('text');\n        expect(result.status).toEqual('200');\n        expect(result.body).toEqual(body);\n      }\n    });\n\n    it('should return the correct mapping for the response when base64', () => {\n      const options: CloudFrontRequestEvent[] = [\n        createLambdaEdgeOriginEvent('GET', '/users'),\n        createLambdaEdgeViewerEvent('GET', '/products'),\n      ];\n\n      for (const event of options) {\n        const cloudFrontRequest = event.Records[0].cf.request;\n        const body = Buffer.from(JSON.stringify(cloudFrontRequest)).toString(\n          'base64',\n        );\n\n        const result = adapter.getResponse({\n          event,\n          body,\n          headers: {\n            Test: 'value',\n            Single: ['2'],\n            Test2: ['1', '2'],\n          },\n          log: {} as ILogger,\n          statusCode: 200,\n          isBase64Encoded: true,\n        });\n\n        expect(result).toBeDefined();\n        expect(result.headers).toEqual({\n          test: [{ key: 'Test', value: 'value' }],\n          single: [{ key: 'Single', value: '2' }],\n          test2: [\n            { key: 'Test2', value: '1' },\n            { key: 'Test2', value: '2' },\n          ],\n        });\n        expect(result.bodyEncoding).toEqual('base64');\n        expect(result.status).toEqual('200');\n        expect(result.body).toEqual(body);\n      }\n    });\n\n    it('should return the correct mapping for the response even if we reach the max response size', () => {\n      const bigResponseForOrigin = new Array(\n        DEFAULT_ORIGIN_MAX_RESPONSE_SIZE_IN_BYTES + 1,\n      ).map(() => 'a');\n      const bigResponseForView = new Array(\n        DEFAULT_VIEWER_MAX_RESPONSE_SIZE_IN_BYTES + 1,\n      ).map(() => 'b');\n\n      const options: CloudFrontRequestEvent[] = [\n        createLambdaEdgeOriginEvent('GET', '/users', {\n          bigResponseForOrigin,\n        }),\n        createLambdaEdgeViewerEvent('GET', '/products', {\n          bigResponseForView,\n        }),\n      ];\n\n      for (const event of options) {\n        const cloudFrontRequest = event.Records[0].cf.request;\n        const body = JSON.stringify(cloudFrontRequest);\n\n        const log = {\n          error: vitest.fn(message =>\n            expect(message).toContain('Max response size exceeded'),\n          ) as any,\n        } as ILogger;\n\n        adapter.getResponse({\n          event,\n          body,\n          headers: {},\n          log,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(log.error).toHaveBeenCalledTimes(1);\n      }\n    });\n\n    it('should return the correct mapping for the response with option \"disallowedHeaders\"', () => {\n      const disallowedHeadersList =\n        DEFAULT_LAMBDA_EDGE_DISALLOWED_HEADERS.filter(\n          header => typeof header === 'string',\n        ) as string[];\n\n      expect(disallowedHeadersList.length > 0).toBe(true);\n\n      const allDisallowedHeadersMap: SingleValueHeaders = {};\n      const allDisallowedMultiValueHeadersMap: MultiValueHeaders = {};\n\n      for (const header of disallowedHeadersList) {\n        allDisallowedHeadersMap[header] = Math.random().toString();\n        allDisallowedMultiValueHeadersMap[header] = [Math.random().toString()];\n      }\n\n      const options: [\n        adapter: RequestLambdaEdgeAdapter,\n        event: CloudFrontRequestEvent,\n        headers: BothValueHeaders,\n      ][] = [\n        [\n          new RequestLambdaEdgeAdapter({\n            disallowedHeaders: disallowedHeadersList,\n          }),\n          createLambdaEdgeOriginEvent('GET', '/products', undefined),\n          allDisallowedHeadersMap,\n        ],\n        [\n          new RequestLambdaEdgeAdapter({\n            disallowedHeaders: disallowedHeadersList,\n          }),\n          createLambdaEdgeOriginEvent('GET', '/products', undefined),\n          allDisallowedMultiValueHeadersMap,\n        ],\n      ];\n\n      for (const [customAdapter, event, headers] of options) {\n        const cloudFrontRequest = event.Records[0].cf.request;\n        const body = JSON.stringify(cloudFrontRequest);\n\n        const result = customAdapter.getResponse({\n          event,\n          body,\n          headers,\n          log: {} as ILogger,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(Object.keys(result.headers!)).toHaveLength(0);\n      }\n    });\n\n    it('should return the correct mapping for the response with option \"shouldStripHeader\"', () => {\n      const customAdapter = new RequestLambdaEdgeAdapter({\n        shouldStripHeader: () => true,\n      });\n\n      const options: [\n        event: CloudFrontRequestEvent,\n        headers: BothValueHeaders,\n      ][] = [\n        [createLambdaEdgeViewerEvent('GET', '/users'), { test: '1' }],\n        [\n          createLambdaEdgeOriginEvent('GET', '/products'),\n          { test: '2', potato: ['3', '4'] },\n        ],\n      ];\n\n      for (const [event, headers] of options) {\n        const cloudFrontRequest = event.Records[0].cf.request;\n        const body = JSON.stringify(cloudFrontRequest);\n\n        const result = customAdapter.getResponse({\n          event,\n          body,\n          headers,\n          log: {} as ILogger,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(Object.keys(result.headers!)).toHaveLength(0);\n      }\n    });\n\n    it('should return the correct mapping for the response with option \"onResponseSizeExceedLimit\"', () => {\n      const customAdapter = new RequestLambdaEdgeAdapter({\n        originMaxResponseSizeInBytes: 0,\n        viewerMaxResponseSizeInBytes: 0,\n      });\n\n      const options: CloudFrontRequestEvent[] = [\n        createLambdaEdgeViewerEvent('GET', '/users', { potato: true }),\n        createLambdaEdgeOriginEvent('GET', '/products', { apple: true }),\n      ];\n\n      for (const event of options) {\n        const cloudFrontRequest = event.Records[0].cf.request;\n        const body = JSON.stringify(cloudFrontRequest);\n\n        const log = {\n          error: vitest.fn(message =>\n            expect(message).toContain('Max response size exceeded'),\n          ) as any,\n        } as ILogger;\n\n        const result = customAdapter.getResponse({\n          event,\n          body,\n          headers: {},\n          log,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(result).toBeDefined();\n        expect(log.error).toHaveBeenCalledTimes(1);\n\n        const onResponseSizeExceedLimit = vitest.fn();\n\n        const customAdapter2 = new RequestLambdaEdgeAdapter({\n          originMaxResponseSizeInBytes: 0,\n          viewerMaxResponseSizeInBytes: 0,\n          onResponseSizeExceedLimit,\n        });\n\n        customAdapter2.getResponse({\n          event,\n          body,\n          headers: {},\n          log: {} as ILogger,\n          statusCode: 200,\n          isBase64Encoded: false,\n        });\n\n        expect(onResponseSizeExceedLimit).toHaveBeenCalled();\n      }\n    });\n  });\n\n  describe('onErrorWhileForwarding', () => {\n    it('should resolver call succeed', () => {\n      const options: [\n        event: CloudFrontRequestEvent,\n        respondWithError: boolean,\n      ][] = [\n        [createLambdaEdgeViewerEvent('GET', '/users', { potato: true }), false],\n        [createLambdaEdgeOriginEvent('GET', '/users', { apple: true }), false],\n        [createLambdaEdgeViewerEvent('GET', '/products'), true],\n        [createLambdaEdgeOriginEvent('GET', '/juices'), true],\n      ];\n\n      for (const [event, respondWithErrors] of options) {\n        const log = {} as ILogger;\n\n        const resolver: DelegatedResolver<CloudFrontRequestResult> = {\n          fail: vitest.fn(),\n          succeed: vitest.fn(),\n        };\n\n        const error = new Error('Test error');\n\n        adapter.onErrorWhileForwarding({\n          event,\n          log,\n          delegatedResolver: resolver,\n          respondWithErrors,\n          error,\n        });\n\n        expect(resolver.fail).toHaveBeenCalledTimes(0);\n        expect(resolver.succeed).toHaveBeenCalledTimes(1);\n      }\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/aws/s3.adapter.spec.ts",
    "content": "import { beforeEach, describe, expect, it } from 'vitest';\nimport { getEventBodyAsBuffer } from '../../../src';\nimport { S3Adapter } from '../../../src/adapters/aws';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport { createS3Event } from './utils/s3';\n\ndescribe(S3Adapter.name, () => {\n  let adapter!: S3Adapter;\n\n  beforeEach(() => {\n    adapter = new S3Adapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(S3Adapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(() => new S3Adapter(), undefined);\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const event = createS3Event();\n\n      const result = adapter.getRequest(event);\n\n      expect(result.method).toBe('POST');\n      expect(result.path).toBe('/s3');\n      expect(result.headers).toHaveProperty('host', 's3.amazonaws.com');\n      expect(result.headers).toHaveProperty('content-type', 'application/json');\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(event),\n        false,\n      );\n\n      expect(result.body).toBeInstanceOf(Buffer);\n      expect(result.body).toStrictEqual(bodyBuffer);\n\n      expect(result.headers).toHaveProperty(\n        'content-length',\n        String(contentLength),\n      );\n    });\n\n    it('should return the correct mapping for the request with custom path and method', () => {\n      const event = createS3Event();\n\n      const method = 'PUT';\n      const path = '/custom/s3';\n\n      const customAdapter = new S3Adapter({\n        s3ForwardMethod: method,\n        s3ForwardPath: path,\n      });\n\n      const result = customAdapter.getRequest(event);\n\n      expect(result.method).toBe(method);\n      expect(result.path).toBe(path);\n      expect(result.headers).toHaveProperty('host', 's3.amazonaws.com');\n      expect(result.headers).toHaveProperty('content-type', 'application/json');\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(event),\n        false,\n      );\n\n      expect(result.body).toBeInstanceOf(Buffer);\n      expect(result.body).toStrictEqual(bodyBuffer);\n\n      expect(result.headers).toHaveProperty(\n        'content-length',\n        String(contentLength),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/aws/sns.adapter.spec.ts",
    "content": "import { beforeEach, describe, expect, it } from 'vitest';\nimport { getEventBodyAsBuffer } from '../../../src';\nimport { SNSAdapter } from '../../../src/adapters/aws';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport { createSNSEvent } from './utils/sns';\n\ndescribe(SNSAdapter.name, () => {\n  let adapter!: SNSAdapter;\n\n  beforeEach(() => {\n    adapter = new SNSAdapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(SNSAdapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(() => new SNSAdapter(), undefined);\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const event = createSNSEvent();\n\n      const result = adapter.getRequest(event);\n\n      expect(result.method).toBe('POST');\n      expect(result.path).toBe('/sns');\n      expect(result.headers).toHaveProperty('host', 'sns.amazonaws.com');\n      expect(result.headers).toHaveProperty('content-type', 'application/json');\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(event),\n        false,\n      );\n\n      expect(result.body).toBeInstanceOf(Buffer);\n      expect(result.body).toStrictEqual(bodyBuffer);\n\n      expect(result.headers).toHaveProperty(\n        'content-length',\n        String(contentLength),\n      );\n    });\n\n    it('should return the correct mapping for the request with custom path and method', () => {\n      const event = createSNSEvent();\n\n      const method = 'PUT';\n      const path = '/custom/sns';\n\n      const customAdapter = new SNSAdapter({\n        snsForwardMethod: method,\n        snsForwardPath: path,\n      });\n\n      const result = customAdapter.getRequest(event);\n\n      expect(result.method).toBe(method);\n      expect(result.path).toBe(path);\n      expect(result.headers).toHaveProperty('host', 'sns.amazonaws.com');\n      expect(result.headers).toHaveProperty('content-type', 'application/json');\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(event),\n        false,\n      );\n\n      expect(result.body).toBeInstanceOf(Buffer);\n      expect(result.body).toStrictEqual(bodyBuffer);\n\n      expect(result.headers).toHaveProperty(\n        'content-length',\n        String(contentLength),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/aws/sqs.adapter.spec.ts",
    "content": "import { beforeEach, describe, expect, it } from 'vitest';\nimport { getEventBodyAsBuffer } from '../../../src';\nimport { SQSAdapter } from '../../../src/adapters/aws';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport { createSQSEvent } from './utils/sqs';\n\ndescribe(SQSAdapter.name, () => {\n  let adapter!: SQSAdapter;\n\n  beforeEach(() => {\n    adapter = new SQSAdapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(SQSAdapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(() => new SQSAdapter(), undefined);\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const event = createSQSEvent();\n\n      const result = adapter.getRequest(event);\n\n      expect(result.method).toBe('POST');\n      expect(result.path).toBe('/sqs');\n      expect(result.headers).toHaveProperty('host', 'sqs.amazonaws.com');\n      expect(result.headers).toHaveProperty('content-type', 'application/json');\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(event),\n        false,\n      );\n\n      expect(result.body).toBeInstanceOf(Buffer);\n      expect(result.body).toStrictEqual(bodyBuffer);\n\n      expect(result.headers).toHaveProperty(\n        'content-length',\n        String(contentLength),\n      );\n    });\n\n    it('should return the correct mapping for the request with custom path and method', () => {\n      const event = createSQSEvent();\n\n      const method = 'PUT';\n      const path = '/custom/sqs';\n\n      const customAdapter = new SQSAdapter({\n        sqsForwardMethod: method,\n        sqsForwardPath: path,\n      });\n\n      const result = customAdapter.getRequest(event);\n\n      expect(result.method).toBe(method);\n      expect(result.path).toBe(path);\n      expect(result.headers).toHaveProperty('host', 'sqs.amazonaws.com');\n      expect(result.headers).toHaveProperty('content-type', 'application/json');\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(event),\n        false,\n      );\n\n      expect(result.body).toBeInstanceOf(Buffer);\n      expect(result.body).toStrictEqual(bodyBuffer);\n\n      expect(result.headers).toHaveProperty(\n        'content-length',\n        String(contentLength),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/aws/utils/alb-event.ts",
    "content": "import type { ALBEvent } from 'aws-lambda';\n\n/**\n * Sample event from {@link https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html}\n */\nexport function createAlbEvent(\n  httpMethod: string,\n  path: string,\n  body?: Record<string, unknown>,\n  headers?: Record<string, string>,\n): ALBEvent {\n  return {\n    requestContext: {\n      elb: {\n        targetGroupArn:\n          'arn:aws:elasticloadbalancing:us-east-1:347971939225:targetgroup/aws-s-Targe-RJF5FKWHX6Y8/29425aed99131fd0',\n      },\n    },\n    httpMethod,\n    path,\n    queryStringParameters: {\n      cache: 'true',\n    },\n    headers: {\n      accept: '*/*',\n      'accept-encoding': 'gzip, deflate',\n      'accept-language': 'en-US,en;q=0.9',\n      'cache-control': 'no-cache',\n      connection: 'keep-alive',\n      'content-length': '',\n      'content-type': '',\n      host: 'aws-ser-alb-p9y7dvwm0r42-2135869912.us-east-1.elb.amazonaws.com',\n      origin:\n        'http://aws-ser-alb-p9y7dvwm0r42-2135869912.us-east-1.elb.amazonaws.com',\n      pragma: 'no-cache',\n      referer:\n        'http://aws-ser-alb-p9y7dvwm0r42-2135869912.us-east-1.elb.amazonaws.com/',\n      'user-agent':\n        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36',\n      'x-amzn-trace-id': 'Root=1-5cdf3407-76d73870a87c746001f27090',\n      'x-forwarded-for': '72.21.198.66',\n      'x-forwarded-port': '80',\n      'x-forwarded-proto': 'http',\n      ...headers,\n    },\n    body: body ? JSON.stringify(body) : null,\n    isBase64Encoded: false,\n  };\n}\n\nexport function createAlbEventWithMultiValueHeaders(\n  httpMethod: string,\n  path: string,\n  body?: Record<string, unknown>,\n  headers?: Record<string, string[]>,\n): ALBEvent {\n  return {\n    requestContext: {\n      elb: {\n        targetGroupArn:\n          'arn:aws:elasticloadbalancing:us-east-1:347971939225:targetgroup/aws-s-Targe-RJF5FKWHX6Y8/29425aed99131fd0',\n      },\n    },\n    httpMethod,\n    path,\n    multiValueQueryStringParameters: {\n      cache: ['true'],\n    },\n    multiValueHeaders: {\n      accept: ['*/*'],\n      'accept-encoding': ['gzip, deflate'],\n      'accept-language': ['en-US,en;q=0.9'],\n      'cache-control': ['no-cache'],\n      connection: ['keep-alive'],\n      'content-length': [],\n      'content-type': [],\n      host: ['aws-ser-alb-p9y7dvwm0r42-2135869912.us-east-1.elb.amazonaws.com'],\n      origin: [\n        'http://aws-ser-alb-p9y7dvwm0r42-2135869912.us-east-1.elb.amazonaws.com',\n      ],\n      pragma: ['no-cache'],\n      referer: [\n        'http://aws-ser-alb-p9y7dvwm0r42-2135869912.us-east-1.elb.amazonaws.com/',\n      ],\n      'user-agent': [\n        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36',\n      ],\n      'x-amzn-trace-id': ['Root=1-5cdf3407-76d73870a87c746001f27090'],\n      'x-forwarded-for': ['72.21.198.66'],\n      'x-forwarded-port': ['80'],\n      'x-forwarded-proto': ['http'],\n      ...headers,\n    },\n    body: body ? JSON.stringify(body) : null,\n    isBase64Encoded: false,\n  };\n}\n"
  },
  {
    "path": "test/adapters/aws/utils/api-gateway-v1.ts",
    "content": "import type {\n  APIGatewayProxyEvent,\n  APIGatewayProxyEventQueryStringParameters,\n} from 'aws-lambda/trigger/api-gateway-proxy';\nimport { getMultiValueHeadersMap } from '../../../../src';\n\nexport function createApiGatewayV1(\n  httpMethod: string,\n  path: string,\n  body?: Record<string, unknown>,\n  headers?: Record<string, string>,\n  queryParams?: APIGatewayProxyEventQueryStringParameters,\n): APIGatewayProxyEvent {\n  return {\n    resource: '/{proxy+}',\n    path,\n    httpMethod,\n    headers: {\n      Accept: '*/*',\n      'Accept-Encoding': 'gzip',\n      'Accept-Language': 'en-US,en;q=0.9',\n      'cache-control': 'no-cache',\n      'CloudFront-Forwarded-Proto': 'https',\n      'CloudFront-Is-Desktop-Viewer': 'true',\n      'CloudFront-Is-Mobile-Viewer': 'false',\n      'CloudFront-Is-SmartTV-Viewer': 'false',\n      'CloudFront-Is-Tablet-Viewer': 'false',\n      'CloudFront-Viewer-Country': 'US',\n      'content-type': '',\n      Host: 'xxxxxx.execute-api.us-east-1.amazonaws.com',\n      origin: 'https://xxxxxx.execute-api.us-east-1.amazonaws.com',\n      pragma: 'no-cache',\n      Referer: 'https://xxxxxx.execute-api.us-east-1.amazonaws.com/prod/',\n      'User-Agent':\n        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36',\n      Via: '2.0 00f0a41f749793b9dd653153037c957e.cloudfront.net (CloudFront)',\n      'X-Amz-Cf-Id': '2D5N65SYHJdnJfEmAV_hC0Mw3QvkbUXDumJKAL786IGHRdq_MggPtA==',\n      'X-Amzn-Trace-Id': 'Root=1-5cdf30d0-31a428004abe13807f9445b0',\n      'X-Forwarded-For': '11.111.111.111, 11.111.111.111',\n      'X-Forwarded-Port': '443',\n      'X-Forwarded-Proto': 'https',\n      ...headers,\n    },\n    multiValueHeaders: {\n      Accept: ['*/*'],\n      'Accept-Encoding': ['gzip', 'deflate', 'br'],\n      'Accept-Language': ['en-US,en;q=0.9'],\n      'cache-control': ['no-cache'],\n      'CloudFront-Forwarded-Proto': ['https'],\n      'CloudFront-Is-Desktop-Viewer': ['true'],\n      'CloudFront-Is-Mobile-Viewer': ['false'],\n      'CloudFront-Is-SmartTV-Viewer': ['false'],\n      'CloudFront-Is-Tablet-Viewer': ['false'],\n      'CloudFront-Viewer-Country': ['US'],\n      'content-type': [],\n      Host: ['xxxxxx.execute-api.us-east-1.amazonaws.com'],\n      origin: ['https://xxxxxx.execute-api.us-east-1.amazonaws.com'],\n      pragma: ['no-cache'],\n      Referer: ['https://xxxxxx.execute-api.us-east-1.amazonaws.com/prod/'],\n      'User-Agent': [\n        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36',\n      ],\n      Via: ['2.0 00f0a41f749793b9dd653153037c957e.cloudfront.net (CloudFront)'],\n      'X-Amz-Cf-Id': [\n        '2D5N65SYHJdnJfEmAV_hC0Mw3QvkbUXDumJKAL786IGHRdq_MggPtA==',\n      ],\n      'X-Amzn-Trace-Id': ['Root=1-5cdf30d0-31a428004abe13807f9445b0'],\n      'X-Forwarded-For': ['11.111.111.111, 11.111.111.111'],\n      'X-Forwarded-Port': ['443'],\n      'X-Forwarded-Proto': ['https'],\n      ...(headers && getMultiValueHeadersMap(headers)),\n    },\n    queryStringParameters: queryParams || null,\n    multiValueQueryStringParameters:\n      (queryParams && getMultiValueHeadersMap(queryParams)) || null,\n    pathParameters: {\n      path: path.replace(/^\\//, ''),\n    },\n    stageVariables: {},\n    requestContext: {\n      authorizer: {\n        claims: null,\n        scopes: null,\n      },\n      resourceId: 'xxxxx',\n      resourcePath: '/{proxy+}',\n      httpMethod: 'POST',\n      extendedRequestId: 'Z2SQlEORIAMFjpA=',\n      requestTime: '17/May/2019:22:08:16 +0000',\n      path,\n      accountId: 'xxxxxxxx',\n      protocol: 'HTTP/1.1',\n      stage: 'prod',\n      domainPrefix: 'xxxxxx',\n      requestTimeEpoch: 1558130896565,\n      requestId: '4589cf16-78f0-11e9-9c65-816a9b037cec',\n      identity: {\n        apiKey: null,\n        apiKeyId: null,\n        clientCert: null,\n        cognitoIdentityPoolId: null,\n        accountId: null,\n        cognitoIdentityId: null,\n        caller: null,\n        sourceIp: '11.111.111.111',\n        principalOrgId: null,\n        accessKey: null,\n        cognitoAuthenticationType: null,\n        cognitoAuthenticationProvider: null,\n        userArn: null,\n        userAgent:\n          'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36',\n        user: null,\n      },\n      domainName: 'xxxxxx.execute-api.us-east-1.amazonaws.com',\n      apiId: 'xxxxxx',\n    },\n    body: (body && JSON.stringify(body)) || null,\n    isBase64Encoded: false,\n  };\n}\n"
  },
  {
    "path": "test/adapters/aws/utils/api-gateway-v2.ts",
    "content": "import type { APIGatewayProxyEventV2 } from 'aws-lambda';\nimport type { APIGatewayProxyEventQueryStringParameters } from 'aws-lambda/trigger/api-gateway-proxy';\nimport { getQueryParamsStringFromRecord } from '../../../../src';\n\nexport function createApiGatewayV2(\n  method: string,\n  path: string,\n  body?: Record<string, unknown>,\n  headers?: Record<string, string>,\n  queryParams?: APIGatewayProxyEventQueryStringParameters,\n  cookies?: APIGatewayProxyEventV2['cookies'],\n): APIGatewayProxyEventV2 {\n  return {\n    version: '2.0',\n    routeKey: '$default',\n    rawPath: path,\n    rawQueryString: getQueryParamsStringFromRecord(queryParams || {}),\n    queryStringParameters: queryParams,\n    headers: {\n      accept:\n        'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',\n      'accept-encoding': 'gzip, deflate, br',\n      'accept-language': 'en-US,en;q=0.9',\n      'cache-control': 'max-age=0',\n      'content-length': '0',\n      host: '6bwvllq3t2.execute-api.us-east-1.amazonaws.com',\n      'sec-fetch-dest': 'document',\n      'sec-fetch-mode': 'navigate',\n      'sec-fetch-site': 'none',\n      'sec-fetch-user': '?1',\n      'upgrade-insecure-requests': '1',\n      'user-agent':\n        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',\n      'x-amzn-trace-id': 'Root=1-5ff59707-4914805430277a6209549a59',\n      'x-forwarded-for': '203.123.103.37',\n      'x-forwarded-port': '443',\n      'x-forwarded-proto': 'https',\n      ...headers,\n    },\n    cookies,\n    requestContext: {\n      accountId: '347971939225',\n      apiId: '6bwvllq3t2',\n      domainName: '6bwvllq3t2.execute-api.us-east-1.amazonaws.com',\n      domainPrefix: '6bwvllq3t2',\n      http: {\n        method,\n        path,\n        protocol: 'HTTP/1.1',\n        sourceIp: '203.123.103.37',\n        userAgent:\n          'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',\n      },\n      requestId: 'YuSJQjZfoAMESbg=',\n      routeKey: '$default',\n      stage: '$default',\n      time: '06/Jan/2021:10:55:03 +0000',\n      timeEpoch: 1609930503973,\n    },\n    body: (body && JSON.stringify(body)) || undefined,\n    isBase64Encoded: false,\n  };\n}\n"
  },
  {
    "path": "test/adapters/aws/utils/dynamodb.ts",
    "content": "import type { DynamoDBStreamEvent } from 'aws-lambda';\n\n/**\n * Sample event from {@link https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html}\n */\nexport function createDynamoDBEvent(): DynamoDBStreamEvent {\n  return {\n    Records: [\n      {\n        eventID: '1',\n        eventVersion: '1.0',\n        dynamodb: {\n          Keys: {\n            Id: {\n              N: '101',\n            },\n          },\n          NewImage: {\n            Message: {\n              S: 'New item!',\n            },\n            Id: {\n              N: '101',\n            },\n          },\n          StreamViewType: 'NEW_AND_OLD_IMAGES',\n          SequenceNumber: '111',\n          SizeBytes: 26,\n        },\n        awsRegion: 'us-west-2',\n        eventName: 'INSERT',\n        eventSourceARN: 'arn:aws:dynamodb:us-east-1:0000000000:mytable',\n        eventSource: 'aws:dynamodb',\n      },\n      {\n        eventID: '2',\n        eventVersion: '1.0',\n        dynamodb: {\n          OldImage: {\n            Message: {\n              S: 'New item!',\n            },\n            Id: {\n              N: '101',\n            },\n          },\n          SequenceNumber: '222',\n          Keys: {\n            Id: {\n              N: '101',\n            },\n          },\n          SizeBytes: 59,\n          NewImage: {\n            Message: {\n              S: 'This item has changed',\n            },\n            Id: {\n              N: '101',\n            },\n          },\n          StreamViewType: 'NEW_AND_OLD_IMAGES',\n        },\n        awsRegion: 'us-west-2',\n        eventName: 'MODIFY',\n        eventSourceARN: 'arn:aws:dynamodb:us-east-1:0000000000:mytable',\n        eventSource: 'aws:dynamodb',\n      },\n    ],\n  };\n}\n"
  },
  {
    "path": "test/adapters/aws/utils/event-bridge.ts",
    "content": "import type { EventBridgeEvent } from 'aws-lambda';\n\n/**\n * Sample event from {@link https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents.html}\n */\nexport function createEventBridgeEvent(): EventBridgeEvent<any, any> {\n  return {\n    version: '0',\n    id: 'fe8d3c65-xmpl-c5c3-2c87-81584709a377',\n    'detail-type': 'RDS DB Instance Event',\n    source: 'aws.rds',\n    account: '123456789012',\n    time: '2020-04-28T07:20:20Z',\n    region: 'us-east-2',\n    resources: ['arn:aws:rds:us-east-2:123456789012:db:rdz6xmpliljlb1'],\n    detail: {\n      EventCategories: ['backup'],\n      SourceType: 'DB_INSTANCE',\n      SourceArn: 'arn:aws:rds:us-east-2:123456789012:db:rdz6xmpliljlb1',\n      Date: '2020-04-28T07:20:20.112Z',\n      Message: 'Finished DB Instance backup',\n      SourceIdentifier: 'rdz6xmpliljlb1',\n    },\n  };\n}\n\n/**\n * Sample event from {@link https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents.html}\n */\nexport function createEventBridgeEventSimple(): EventBridgeEvent<any, any> {\n  return {\n    version: '0',\n    account: '123456789012',\n    region: 'us-east-2',\n    detail: {},\n    'detail-type': 'Scheduled Event',\n    source: 'aws.events',\n    time: '2019-03-01T01:23:45Z',\n    id: 'cdc73f9d-aea9-11e3-9d5a-835b769c0d9c',\n    resources: ['arn:aws:events:us-east-2:123456789012:rule/my-schedule'],\n  };\n}\n"
  },
  {
    "path": "test/adapters/aws/utils/events.ts",
    "content": "import {\n  AlbAdapter,\n  ApiGatewayV1Adapter,\n  ApiGatewayV2Adapter,\n  DynamoDBAdapter,\n  EventBridgeAdapter,\n  LambdaEdgeAdapter,\n  S3Adapter,\n  SNSAdapter,\n  SQSAdapter,\n} from '../../../../src/adapters/aws';\nimport {\n  createAlbEvent,\n  createAlbEventWithMultiValueHeaders,\n} from './alb-event';\nimport { createApiGatewayV1 } from './api-gateway-v1';\nimport { createApiGatewayV2 } from './api-gateway-v2';\nimport { createDynamoDBEvent } from './dynamodb';\nimport {\n  createEventBridgeEvent,\n  createEventBridgeEventSimple,\n} from './event-bridge';\nimport {\n  createLambdaEdgeOriginEvent,\n  createLambdaEdgeViewerEvent,\n} from './lambda-edge';\nimport { createS3Event } from './s3';\nimport { createSNSEvent } from './sns';\nimport { createSQSEvent } from './sqs';\n\nexport const allAWSEvents: Array<[string, any]> = [\n  ['fake-to-test-undefined-event', undefined],\n  ['fake-to-test-records-empty-event', { Records: [] }],\n  [\n    AlbAdapter.name,\n    createAlbEvent('POST', '/users', { name: 'potato with banana' }),\n  ],\n  [\n    AlbAdapter.name,\n    createAlbEventWithMultiValueHeaders('PUT', '/users', { name: 'batata' }),\n  ],\n  [AlbAdapter.name, createAlbEvent('GET', '/users')],\n  [AlbAdapter.name, createAlbEventWithMultiValueHeaders('GET', '/users')],\n  [\n    ApiGatewayV1Adapter.name,\n    createApiGatewayV1('POST', '/users', { name: 'Fake' }),\n  ],\n  [\n    ApiGatewayV1Adapter.name,\n    createApiGatewayV1('PUT', '/users', { name: 'Fake v2' }),\n  ],\n  [\n    ApiGatewayV1Adapter.name,\n    createApiGatewayV1('GET', '/users', undefined, {}, { page: '2' }),\n  ],\n  [ApiGatewayV2Adapter.name, createApiGatewayV2('GET', '/collaborators')],\n  [\n    ApiGatewayV2Adapter.name,\n    createApiGatewayV2('POST', '/collaborators', { name: 'Fake' }),\n  ],\n  [\n    ApiGatewayV2Adapter.name,\n    createApiGatewayV2('PUT', '/collaborators', { name: 'Fake v2' }),\n  ],\n  [\n    ApiGatewayV2Adapter.name,\n    createApiGatewayV2('GET', '/collaborators', undefined, {}, { page: '2' }),\n  ],\n  [ApiGatewayV2Adapter.name, createApiGatewayV2('collaborators', '/users')],\n  [DynamoDBAdapter.name, createDynamoDBEvent()],\n  [EventBridgeAdapter.name, createEventBridgeEvent()],\n  [EventBridgeAdapter.name, createEventBridgeEventSimple()],\n  [SQSAdapter.name, createSQSEvent()],\n  [SNSAdapter.name, createSNSEvent()],\n  [LambdaEdgeAdapter.name, createLambdaEdgeViewerEvent('GET', '/image.png')],\n  [\n    LambdaEdgeAdapter.name,\n    createLambdaEdgeViewerEvent('POST', '/image.png', {\n      base64: Buffer.from('batata', 'utf-8').toString('base64'),\n    }),\n  ],\n  [LambdaEdgeAdapter.name, createLambdaEdgeOriginEvent('GET', '/image.png')],\n  [\n    LambdaEdgeAdapter.name,\n    createLambdaEdgeOriginEvent('POST', '/image.png', {\n      base64: Buffer.from('batata', 'utf-8').toString('base64'),\n    }),\n  ],\n  [S3Adapter.name, createS3Event()],\n];\n"
  },
  {
    "path": "test/adapters/aws/utils/lambda-edge.ts",
    "content": "import type { CloudFrontHeaders } from 'aws-lambda/common/cloudfront';\nimport type { CloudFrontRequestEvent } from 'aws-lambda/trigger/cloudfront-request';\n\nexport function createLambdaEdgeViewerEvent(\n  httpMethod: string,\n  path: string,\n  body?: Record<string, unknown>,\n  headers?: CloudFrontHeaders,\n  queryParams?: string,\n): CloudFrontRequestEvent {\n  return {\n    Records: [\n      {\n        cf: {\n          config: {\n            distributionDomainName: 'd3qj9vk9486y6c.cloudfront.net',\n            distributionId: 'E2I5C7O4FEQEKZ',\n            eventType: 'viewer-request',\n            requestId:\n              'BKXC0kFgBfWSEgribSo9EwziZB1FztiXQ96VRvTfFNHYCBv7Ko-RBQ==',\n          },\n          request: {\n            clientIp: '203.123.103.37',\n            headers: headers ?? {\n              host: [\n                {\n                  key: 'Host',\n                  value: 'd3qj9vk9486y6c.cloudfront.net',\n                },\n              ],\n              'user-agent': [\n                {\n                  key: 'User-Agent',\n                  value:\n                    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36',\n                },\n              ],\n              'cache-control': [\n                {\n                  key: 'Cache-Control',\n                  value: 'max-age=0',\n                },\n              ],\n              accept: [\n                {\n                  key: 'accept',\n                  value:\n                    'application/json,text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',\n                },\n              ],\n              'if-none-match': [\n                {\n                  key: 'if-none-match',\n                  value: 'W/\"2e-Lu6qxFOQSPFulDAGUFiiK6QgREo\"',\n                },\n              ],\n              'accept-language': [\n                {\n                  key: 'accept-language',\n                  value: 'en-US,en;q=0.9',\n                },\n              ],\n              'upgrade-insecure-requests': [\n                {\n                  key: 'upgrade-insecure-requests',\n                  value: '1',\n                },\n              ],\n              origin: [\n                {\n                  key: 'Origin',\n                  value: 'https://d3qj9vk9486y6c.cloudfront.net',\n                },\n              ],\n              'sec-fetch-site': [\n                {\n                  key: 'Sec-Fetch-Site',\n                  value: 'same-origin',\n                },\n              ],\n              'sec-fetch-mode': [\n                {\n                  key: 'Sec-Fetch-Mode',\n                  value: 'cors',\n                },\n              ],\n              'sec-fetch-dest': [\n                {\n                  key: 'Sec-Fetch-Dest',\n                  value: 'empty',\n                },\n              ],\n              referer: [\n                {\n                  key: 'Referer',\n                  value: 'https://d3qj9vk9486y6c.cloudfront.net/users',\n                },\n              ],\n              'accept-encoding': [\n                {\n                  key: 'Accept-Encoding',\n                  value: 'gzip, deflate, br',\n                },\n              ],\n            },\n            body: body\n              ? {\n                  action: 'read-only',\n                  encoding: 'base64',\n                  inputTruncated: false,\n                  data: Buffer.from(JSON.stringify(body), 'utf-8').toString(\n                    'base64',\n                  ),\n                }\n              : undefined,\n            method: httpMethod,\n            querystring: queryParams || '',\n            uri: path,\n          },\n        },\n      },\n    ],\n  };\n}\n\nexport function createLambdaEdgeOriginEvent(\n  httpMethod: string,\n  path: string,\n  body?: Record<string, unknown>,\n  headers?: CloudFrontHeaders,\n  queryParams?: string,\n): CloudFrontRequestEvent {\n  return {\n    Records: [\n      {\n        cf: {\n          config: {\n            distributionDomainName: 'd111111abcdef8.cloudfront.net',\n            distributionId: 'EDFDVBD6EXAMPLE',\n            eventType: 'origin-request',\n            requestId:\n              '4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ==',\n          },\n          request: {\n            body: body\n              ? {\n                  action: 'read-only',\n                  encoding: 'base64',\n                  inputTruncated: false,\n                  data: Buffer.from(JSON.stringify(body), 'utf-8').toString(\n                    'base64',\n                  ),\n                }\n              : undefined,\n            clientIp: '203.0.113.178',\n            headers: headers ?? {\n              'x-forwarded-for': [\n                {\n                  key: 'X-Forwarded-For',\n                  value: '203.0.113.178',\n                },\n              ],\n              'user-agent': [\n                {\n                  key: 'User-Agent',\n                  value: 'Amazon CloudFront',\n                },\n              ],\n              via: [\n                {\n                  key: 'Via',\n                  value:\n                    '2.0 2afae0d44e2540f472c0635ab62c232b.cloudfront.net (CloudFront)',\n                },\n              ],\n              host: [\n                {\n                  key: 'Host',\n                  value: 'example.org',\n                },\n              ],\n              'cache-control': [\n                {\n                  key: 'Cache-Control',\n                  value: 'no-cache, cf-no-cache',\n                },\n              ],\n            },\n            method: httpMethod,\n            origin: {\n              custom: {\n                customHeaders: {},\n                domainName: 'example.org',\n                keepaliveTimeout: 5,\n                path: '',\n                port: 443,\n                protocol: 'https',\n                readTimeout: 30,\n                sslProtocols: ['TLSv1', 'TLSv1.1', 'TLSv1.2'],\n              },\n            },\n            querystring: queryParams || '',\n            uri: path,\n          },\n        },\n      },\n    ],\n  };\n}\n"
  },
  {
    "path": "test/adapters/aws/utils/s3.ts",
    "content": "import type { S3Event } from 'aws-lambda';\n\n/**\n * Sample event from {@link https://docs.aws.amazon.com/pt_br/lambda/latest/dg/with-s3.html}\n */\nexport function createS3Event(): S3Event {\n  return {\n    Records: [\n      {\n        eventVersion: '2.1',\n        eventSource: 'aws:s3',\n        awsRegion: 'us-east-2',\n        eventTime: '2019-09-03T19:37:27.192Z',\n        eventName: 'ObjectCreated:Put',\n        userIdentity: {\n          principalId: 'AWS:AIDAINPONIXQXHT3IKHL2',\n        },\n        requestParameters: {\n          sourceIPAddress: '205.255.255.255',\n        },\n        responseElements: {\n          'x-amz-request-id': 'D82B88E5F771F645',\n          'x-amz-id-2':\n            'vlR7PnpV2Ce81l0PRw6jlUpck7Jo5ZsQjryTjKlc5aLWGVHPZLj5NeC6qMa0emYBDXOo6QBU0Wo=',\n        },\n        s3: {\n          s3SchemaVersion: '1.0',\n          configurationId: '828aa6fc-f7b5-4305-8584-487c791949c1',\n          bucket: {\n            name: 'DOC-EXAMPLE-BUCKET',\n            ownerIdentity: {\n              principalId: 'A3I5XTEXAMAI3E',\n            },\n            arn: 'arn:aws:s3:::lambda-artifacts-deafc19498e3f2df',\n          },\n          object: {\n            key: 'b21b84d653bb07b05b1e6b33684dc11b',\n            size: 1305107,\n            eTag: 'b21b84d653bb07b05b1e6b33684dc11b',\n            sequencer: '0C0F6F405D6ED209E1',\n          },\n        },\n      },\n    ],\n  };\n}\n"
  },
  {
    "path": "test/adapters/aws/utils/sns.ts",
    "content": "import type { SNSEvent } from 'aws-lambda';\n\n/**\n * Sample event from {@link https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html}\n */\nexport function createSNSEvent(): SNSEvent {\n  return {\n    Records: [\n      {\n        EventVersion: '1.0',\n        EventSubscriptionArn:\n          'arn:aws:sns:us-east-2:123456789012:sns-lambda:21be56ed-a058-49f5-8c98-aedd2564c486',\n        EventSource: 'aws:sns',\n        Sns: {\n          SignatureVersion: '1',\n          Timestamp: '2019-01-02T12:45:07.000Z',\n          Signature:\n            'tcc6faL2yUC6dgZdmrwh1Y4cGa/ebXEkAi6RibDsvpi+tE/1+82j...65r==',\n          SigningCertUrl:\n            'https://sns.us-east-2.amazonaws.com/SimpleNotificationService-ac565b8b1a6c5d002d285f9598aa1d9b.pem',\n          MessageId: '95df01b4-ee98-5cb9-9903-4c221d41eb5e',\n          Message: 'Hello from SNS!',\n          MessageAttributes: {\n            Test: {\n              Type: 'String',\n              Value: 'TestString',\n            },\n            TestBinary: {\n              Type: 'Binary',\n              Value: 'TestBinary',\n            },\n          },\n          Type: 'Notification',\n          UnsubscribeUrl:\n            'https://sns.us-east-2.amazonaws.com/?Action=Unsubscribe&amp;SubscriptionArn=arn:aws:sns:us-east-2:123456789012:test-lambda:21be56ed-a058-49f5-8c98-aedd2564c486',\n          TopicArn: 'arn:aws:sns:us-east-2:123456789012:sns-lambda',\n          Subject: 'TestInvoke',\n        },\n      },\n    ],\n  };\n}\n"
  },
  {
    "path": "test/adapters/aws/utils/sqs.ts",
    "content": "import type { SQSEvent } from 'aws-lambda';\n\n/**\n * Sample event from {@link https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html}\n */\nexport function createSQSEvent(): SQSEvent {\n  return {\n    Records: [\n      {\n        messageId: '059f36b4-87a3-44ab-83d2-661975830a7d',\n        receiptHandle: 'AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...',\n        body: 'Test message.',\n        attributes: {\n          ApproximateReceiveCount: '1',\n          SentTimestamp: '1545082649183',\n          SenderId: 'AIDAIENQZJOLO23YVJ4VO',\n          ApproximateFirstReceiveTimestamp: '1545082649185',\n        },\n        messageAttributes: {},\n        md5OfBody: 'e4e68fb7bd0e697a0ae8f1bb342846b3',\n        eventSource: 'aws:sqs',\n        eventSourceARN: 'arn:aws:sqs:us-east-2:123456789012:my-queue',\n        awsRegion: 'us-east-2',\n      },\n    ],\n  };\n}\n"
  },
  {
    "path": "test/adapters/azure/http-trigger.adapter.spec.ts",
    "content": "import type { Cookie, HttpRequest, HttpResponseSimple } from '@azure/functions';\nimport { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport {\n  type DelegatedResolver,\n  type GetResponseAdapterProps,\n  type ILogger,\n  getEventBodyAsBuffer,\n  getFlattenedHeadersMap,\n  getPathWithQueryStringParams,\n} from '../../../src';\nimport { HttpTriggerV4Adapter } from '../../../src/adapters/azure';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport {\n  createHttpTriggerContext,\n  createHttpTriggerEvent,\n} from './utils/http-trigger';\n\ndescribe(HttpTriggerV4Adapter.name, () => {\n  let adapter!: HttpTriggerV4Adapter;\n\n  beforeEach(() => {\n    adapter = new HttpTriggerV4Adapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(HttpTriggerV4Adapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(\n    () => new HttpTriggerV4Adapter(),\n    createHttpTriggerContext('GET', '/'),\n  );\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const method = 'PUT';\n      const path = '/events';\n      const body = { name: 'H4ad Event' };\n\n      const event = createHttpTriggerEvent(method, path, body);\n\n      expect(event.headers).toHaveProperty('x-forwarded-for');\n      expect(event.headers['x-forwarded-for']).not.toBeInstanceOf(Array);\n\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.headers['x-forwarded-for'];\n\n      expect(result).toHaveProperty('method', method);\n\n      expect(result).toHaveProperty('headers');\n      expect(result.headers).toHaveProperty('x-forwarded-for');\n      expect(result.headers['x-forwarded-for']).not.toBeInstanceOf(Array);\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).toBeInstanceOf(Buffer);\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(body),\n        false,\n      );\n      expect(result.body).toStrictEqual(bodyBuffer);\n      expect(result.headers).toHaveProperty('content-length');\n      expect(result.headers['content-length']).toBe(String(contentLength));\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(path, event.query);\n\n      expect(result.path.replace('/api/test-serverless-adapter', '')).toEqual(\n        resultPath,\n      );\n    });\n\n    it('should return the correct mapping for the request when it has no body', () => {\n      const method = 'POST';\n      const path = '/events';\n      const body = undefined;\n\n      const event = createHttpTriggerEvent(method, path, body);\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.headers['x-forwarded-for'];\n\n      expect(result).toHaveProperty('method', method);\n\n      expect(result).toHaveProperty('headers');\n      expect(result.headers).toHaveProperty('x-forwarded-for');\n      expect(result.headers['x-forwarded-for']).not.toBeInstanceOf(Array);\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).not.toBeInstanceOf(Buffer);\n      expect(result.body).toBeUndefined();\n\n      expect(result.headers).not.toHaveProperty('content-length');\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(path, event.query);\n      expect(result.path.replace('/api/test-serverless-adapter', '')).toEqual(\n        resultPath,\n      );\n    });\n\n    it('should return the correct mapping for the request when send stripBasePath', () => {\n      const stripBasePath = '/api/test-serverless-adapter';\n\n      const method = 'PUT';\n      const path = '/events';\n      const body = { name: 'H4ad Event' };\n\n      const strippedAdapter = new HttpTriggerV4Adapter({ stripBasePath });\n\n      const event = createHttpTriggerEvent(method, path, body);\n\n      expect(event.headers).toHaveProperty('x-forwarded-for');\n      expect(event.headers['x-forwarded-for']).not.toBeInstanceOf(Array);\n\n      const result = strippedAdapter.getRequest(event);\n\n      const remoteAddress = event.headers['x-forwarded-for'];\n\n      expect(result).toHaveProperty('method', method);\n\n      expect(result).toHaveProperty('headers');\n      expect(result.headers).toHaveProperty('x-forwarded-for');\n      expect(result.headers['x-forwarded-for']).not.toBeInstanceOf(Array);\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).toBeInstanceOf(Buffer);\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(body),\n        false,\n      );\n      expect(result.body).toStrictEqual(bodyBuffer);\n      expect(result.headers).toHaveProperty('content-length');\n      expect(result.headers['content-length']).toBe(String(contentLength));\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(path, event.query);\n\n      expect(result).toHaveProperty('path', resultPath);\n    });\n  });\n\n  describe('getResponse', () => {\n    it('should return the correct mapping for the response', () => {\n      const method = 'PUT';\n      const path = '/events';\n      const requestBody = { name: 'H4ad Event' };\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createHttpTriggerEvent(method, path, requestBody);\n      const responseHeaders = getFlattenedHeadersMap(event.headers);\n\n      const result = adapter.getResponse({\n        event,\n        headers: responseHeaders,\n        body: resultBody,\n        log: {} as ILogger,\n        isBase64Encoded: resultIsBase64Encoded,\n        statusCode: resultStatusCode,\n      });\n\n      expect(result).toHaveProperty('statusCode', 200);\n      expect(result).toHaveProperty('body', resultBody);\n      expect(result).toHaveProperty('headers', responseHeaders);\n      expect(result).toHaveProperty('enableContentNegotiation', false);\n      expect(result).toHaveProperty('cookies', []);\n    });\n\n    it('should return the correct mapping for the response with multiple set-cookie', () => {\n      const method = 'PUT';\n      const path = '/events';\n      const requestBody = { name: 'H4ad Event' };\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createHttpTriggerEvent(method, path, requestBody, {\n        'set-cookie': [\n          'Id=a3fWa; Expires=Thu, 31 Oct 2021 07:28:00 GMT;',\n          'id=a3fWa; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly',\n          'MyKey=myvalue; SameSite=Strict',\n          'lu=Rg3vHJZnehYLjVg7qi3bZjzg; Expires=Tue, 15 Jan 2013 21:47:38 GMT; Path=/; Domain=.example.com; HttpOnly',\n          'made_write_conn=1295214458; Path=/; Domain=.example.com; Max-Age=1209600',\n          'reg_fb_gate=deleted; Expires=Thu, 01 Jan 1970 00:00:01 GMT; Path=/; Domain=.example.com; HttpOnly',\n        ],\n      });\n\n      const result = adapter.getResponse({\n        event,\n        headers: event.headers,\n        body: resultBody,\n        log: {} as ILogger,\n        isBase64Encoded: resultIsBase64Encoded,\n        statusCode: resultStatusCode,\n      });\n\n      delete event.headers['set-cookie'];\n\n      expect(result).toHaveProperty('statusCode', 200);\n      expect(result).toHaveProperty('body', resultBody);\n      expect(result).toHaveProperty('headers', event.headers);\n      expect(result).toHaveProperty('enableContentNegotiation', false);\n      expect(result.cookies).toStrictEqual([\n        {\n          name: 'Id',\n          value: 'a3fWa',\n          expires: new Date('Thu, 31 Oct 2021 07:28:00 GMT'),\n        },\n        {\n          name: 'id',\n          value: 'a3fWa',\n          expires: new Date('Thu, 21 Oct 2021 07:28:00 GMT'),\n          secure: true,\n          httpOnly: true,\n        },\n        {\n          name: 'MyKey',\n          value: 'myvalue',\n          sameSite: 'Strict',\n        },\n        {\n          name: 'lu',\n          value: 'Rg3vHJZnehYLjVg7qi3bZjzg',\n          expires: new Date('Tue, 15 Jan 2013 21:47:38 GMT'),\n          path: '/',\n          domain: '.example.com',\n          httpOnly: true,\n        },\n        {\n          name: 'made_write_conn',\n          value: '1295214458',\n          path: '/',\n          domain: '.example.com',\n          maxAge: 1209600,\n        },\n        {\n          name: 'reg_fb_gate',\n          value: 'deleted',\n          expires: new Date('Thu, 01 Jan 1970 00:00:01 GMT'),\n          path: '/',\n          domain: '.example.com',\n          httpOnly: true,\n        },\n      ] as Cookie[]);\n    });\n\n    it('should return the correct mapping for the response with set-cookie', () => {\n      const method = 'PUT';\n      const path = '/events';\n      const requestBody = { name: 'H4ad Event' };\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createHttpTriggerEvent(method, path, requestBody, {\n        'set-cookie': 'id=a3fWa; Expires=Thu, 31 Oct 2021 07:28:00 GMT;',\n      });\n\n      const result = adapter.getResponse({\n        event,\n        headers: event.headers,\n        body: resultBody,\n        log: {} as ILogger,\n        isBase64Encoded: resultIsBase64Encoded,\n        statusCode: resultStatusCode,\n      });\n\n      delete event.headers['set-cookie'];\n\n      expect(result).toHaveProperty('statusCode', 200);\n      expect(result).toHaveProperty('body', resultBody);\n      expect(result).toHaveProperty('headers', event.headers);\n      expect(result).toHaveProperty('enableContentNegotiation', false);\n      expect(result.cookies).toStrictEqual([\n        {\n          name: 'id',\n          value: 'a3fWa',\n          expires: new Date('Thu, 31 Oct 2021 07:28:00 GMT'),\n        },\n      ] as Cookie[]);\n    });\n  });\n\n  describe('onErrorWhileForwarding', () => {\n    it('should resolver call succeed', () => {\n      const method = 'GET';\n      const path = '/events';\n      const requestBody = undefined;\n\n      const event = createHttpTriggerEvent(method, path, requestBody);\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<HttpResponseSimple> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = true;\n      const error = new Error('Test error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: HttpResponseSimple | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<HttpRequest>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).toBe(error.stack);\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n\n    it('should resolver call succeed but without sending errors', () => {\n      const method = 'GET';\n      const path = '/events';\n      const requestBody = undefined;\n\n      const event = createHttpTriggerEvent(method, path, requestBody);\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<HttpResponseSimple> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = false;\n      const error = new Error('Test error without sending this error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: HttpResponseSimple | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<HttpRequest>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).not.toBe(error.stack);\n          expect(params.body).toStrictEqual('');\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/azure/utils/events.ts",
    "content": "import { HttpTriggerV4Adapter } from '../../../../src/adapters/azure';\nimport { createHttpTriggerEvent } from './http-trigger';\n\nexport const allAzureEvents: Array<[string, any]> = [\n  [HttpTriggerV4Adapter.name, createHttpTriggerEvent('GET', '/')],\n  [\n    HttpTriggerV4Adapter.name,\n    createHttpTriggerEvent('POST', '/', { name: 'Joga10' }),\n  ],\n];\n"
  },
  {
    "path": "test/adapters/azure/utils/http-trigger.ts",
    "content": "import { URL } from 'url';\nimport type { Context, Form, HttpRequest } from '@azure/functions';\nimport { vitest } from 'vitest';\nimport { type BothValueHeaders } from '../../../../src';\n\nexport function createHttpTriggerEvent(\n  method: HttpRequest['method'],\n  path: string,\n  body?: Record<string, unknown>,\n  headers?: BothValueHeaders,\n): HttpRequest {\n  const url = new URL(`http://localhost${path}`);\n\n  url.searchParams.set('code', 'sE_d8h7XJ4YYsGJ7mgVta_t-32323%3D%3D');\n\n  return {\n    get: () => '',\n    method,\n    url: `https://serverless-adapter.azurewebsites.net/api/test-serverless-adapter${\n      path || ''\n    }?${url.searchParams.toString()}`,\n    headers: {\n      accept:\n        'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',\n      'accept-encoding': 'gzip, deflate, br',\n      'accept-language': 'pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,bg;q=0.6',\n      'cache-control': 'max-age=0',\n      host: 'serverless-adapter.azurewebsites.net',\n      'max-forwards': '9',\n      'user-agent':\n        'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36',\n      'sec-ch-ua':\n        '\".Not/A)Brand\";v=\"99\", \"Google Chrome\";v=\"103\", \"Chromium\";v=\"103\"',\n      'sec-ch-ua-mobile': '?0',\n      'sec-ch-ua-platform': '\"Linux\"',\n      dnt: '1',\n      'sec-fetch-site': 'none',\n      'sec-fetch-mode': 'navigate',\n      'sec-fetch-user': '?1',\n      'sec-fetch-dest': 'document',\n      'x-arr-log-id': '09a0a10e-eaba-487f-9e6b-ae6ce6f1d333',\n      'client-ip': '2.3.3.3:30750',\n      'x-site-deployment-id': 'serverless-adapter',\n      'was-default-hostname': 'serverless-adapter.azurewebsites.net',\n      'x-forwarded-proto': 'https',\n      'x-appservice-proto': 'https',\n      'x-arr-ssl':\n        '2048|256|CN=Microsoft Azure TLS Issuing CA 01, O=Microsoft Corporation, C=US|CN=*.azurewebsites.net, O=Microsoft Corporation, L=Redmond, S=WA, C=US',\n      'x-forwarded-tlsversion': '1.2',\n      'x-forwarded-for': '3.3.3.3:49196',\n      'x-original-url':\n        '/api/test-serverless-adapter?code=sE_d8h7XJ4YYsGJ7mgVta_t-32323%3D%3D',\n      'x-waws-unencoded-url':\n        '/api/test-serverless-adapter?code=sE_d8h7XJ4YYsGJ7mgVta_t-32323%3D%3D',\n      'disguised-host': 'serverless-adapter.azurewebsites.net',\n      ...headers,\n    },\n    query: Object.fromEntries(url.searchParams.entries()),\n    params: {},\n    body: body || undefined,\n    rawBody: body ? JSON.stringify(body) : undefined,\n    user: null,\n    parseFormBody(): Form {\n      throw new Error('test');\n    },\n  };\n}\n\nexport function createHttpTriggerContext(\n  method: HttpRequest['method'],\n  path: string,\n  body?: Record<string, unknown>,\n  headers?: BothValueHeaders,\n): Context {\n  const req = createHttpTriggerEvent(method, path, body, headers);\n\n  const log = vitest.fn();\n\n  Object.assign(log, {\n    error: vitest.fn(),\n    warn: vitest.fn(),\n    info: vitest.fn(),\n    verbose: vitest.fn(),\n  });\n\n  return {\n    invocationId: '6947db6b-98f6-406b-a1ce-e5bd7244ff66',\n    traceContext: {\n      traceparent: '00-7d1ba80dfba92a27453561f5844346c9-684d236d619d3234-00',\n      tracestate: '',\n      attributes: {},\n    },\n    executionContext: {\n      invocationId: '6947db6b-98f6-406b-a1ce-e5bd7244ff66',\n      functionName: 'test-serverless-adapter',\n      functionDirectory: 'C:\\\\home\\\\site\\\\wwwroot\\\\test-serverless-adapter',\n      retryContext: null,\n    },\n    bindings: {\n      req,\n    },\n    log: log as unknown as Context['log'],\n    bindingData: {\n      invocationId: '6947db6b-98f6-406b-a1ce-32323',\n      query: req.query,\n      headers: req.headers,\n      sys: {\n        methodName: 'test-serverless-adapter',\n        utcNow: '2022-07-10T20:48:24.113Z',\n        randGuid: '5a5a0bfd-9774-4e5a-875d-bb8444d595b3',\n      },\n    },\n    bindingDefinitions: [\n      { name: 'req', type: 'httpTrigger', direction: 'in' },\n      { name: 'res', type: 'http', direction: 'out' },\n    ],\n    done: vitest.fn(),\n    req: req,\n    res: {\n      headers: {},\n      cookies: [],\n      send: vitest.fn(),\n      header: vitest.fn(),\n      set: vitest.fn(),\n      get: vitest.fn(),\n      _done: vitest.fn(),\n    },\n  };\n}\n"
  },
  {
    "path": "test/adapters/digital-ocean/http-function.adapter.spec.ts",
    "content": "import { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport {\n  type DelegatedResolver,\n  type GetResponseAdapterProps,\n  type ILogger,\n  getEventBodyAsBuffer,\n  getPathWithQueryStringParams,\n} from '../../../src';\nimport {\n  type DigitalOceanHttpEvent,\n  type DigitalOceanHttpResponse,\n} from '../../../src/@types/digital-ocean';\nimport { HttpFunctionAdapter } from '../../../src/adapters/digital-ocean';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport { createHttpFunctionEvent } from './utils/http-function';\n\ndescribe(HttpFunctionAdapter.name, () => {\n  let adapter!: HttpFunctionAdapter;\n\n  beforeEach(() => {\n    adapter = new HttpFunctionAdapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(HttpFunctionAdapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(() => new HttpFunctionAdapter(), undefined);\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const method = 'PUT';\n      const path = '/collaborators';\n      const body = { name: 'H4ad Collaborator' };\n      const queryParams = { page: '2' };\n\n      const event = createHttpFunctionEvent(\n        method,\n        path,\n        body,\n        {},\n        queryParams,\n      );\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.__ow_headers['x-forwarded-for'];\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).toBeInstanceOf(Buffer);\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(body),\n        false,\n      );\n      expect(result.body).toStrictEqual(bodyBuffer);\n      expect(result.headers).toHaveProperty('content-length');\n      expect(result.headers['content-length']).toBe(String(contentLength));\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(path, event.__ow_query);\n      expect(result).toHaveProperty('path', resultPath);\n    });\n\n    it('should method be always uppercase', () => {\n      const method = 'get';\n      const path = '/test';\n\n      const event = createHttpFunctionEvent(method, path);\n      const result = adapter.getRequest(event);\n\n      expect(result).toHaveProperty('method', method.toUpperCase());\n    });\n\n    it('should return the correct mapping for the request when it has no body', () => {\n      const method = 'GET';\n      const path = '/collaborators';\n      const body = undefined;\n\n      const event = createHttpFunctionEvent(\n        method,\n        path,\n        body,\n        {},\n        { page: '2' },\n      );\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.__ow_headers['x-forwarded-for'];\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n      expect(result).toHaveProperty('body');\n      expect(result.body).not.toBeInstanceOf(Buffer);\n      expect(result.body).toBeUndefined();\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(path, event.__ow_query);\n      expect(result).toHaveProperty('path', resultPath);\n    });\n\n    it('should return the correct mapping for the request when send stripBasePath', () => {\n      const stripBasePath = '/prod';\n\n      const method = 'GET';\n      const path = '/prod/collaborators';\n      const body = undefined;\n\n      const strippedAdapter = new HttpFunctionAdapter({ stripBasePath });\n\n      const event = createHttpFunctionEvent(method, path, body);\n      const result = strippedAdapter.getRequest(event);\n\n      const remoteAddress = event.__ow_headers['x-forwarded-for'];\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).not.toBeInstanceOf(Buffer);\n      expect(result.body).toBeUndefined();\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path.replace('/prod', ''),\n        event.__ow_query,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n  });\n\n  describe('getResponse', () => {\n    it('should return the correct mapping for the response', () => {\n      const method = 'PUT';\n      const path = '/collaborators';\n      const requestBody = { name: 'H4ad Collaborator V2' };\n      const queryParams = { page: '2' };\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createHttpFunctionEvent(\n        method,\n        path,\n        requestBody,\n        {},\n        queryParams,\n      );\n      const resultHeaders = event.__ow_headers;\n\n      const result = adapter.getResponse({\n        event,\n        log: {} as ILogger,\n        body: resultBody,\n        isBase64Encoded: resultIsBase64Encoded,\n        statusCode: resultStatusCode,\n        headers: resultHeaders,\n      });\n\n      expect(result).toHaveProperty('statusCode', 200);\n      expect(result).toHaveProperty('body', resultBody);\n      expect(result).toHaveProperty('headers');\n    });\n  });\n\n  describe('onErrorWhileForwarding', () => {\n    it('should resolver call succeed', () => {\n      const method = 'GET';\n      const path = '/events';\n      const requestBody = undefined;\n\n      const event = createHttpFunctionEvent(method, path, requestBody);\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<DigitalOceanHttpResponse> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = true;\n      const error = new Error('Test error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: DigitalOceanHttpResponse | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<DigitalOceanHttpEvent>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).toBe(error.stack);\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n\n    it('should resolver call succeed but without sending errors', () => {\n      const method = 'GET';\n      const path = '/users';\n      const requestBody = undefined;\n\n      const event = createHttpFunctionEvent(method, path, requestBody);\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<DigitalOceanHttpResponse> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = false;\n      const error = new Error('Test error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: DigitalOceanHttpResponse | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<DigitalOceanHttpEvent>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).toBe('');\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/digital-ocean/utils/event.ts",
    "content": "import { HttpFunctionAdapter } from '../../../../src/adapters/digital-ocean';\nimport { createHttpFunctionEvent } from './http-function';\n\nexport const allDigitalOceanEvents: Array<[string, any]> = [\n  [\n    HttpFunctionAdapter.name,\n    createHttpFunctionEvent('post', '/users', { name: 'test' }),\n  ],\n  [HttpFunctionAdapter.name, createHttpFunctionEvent('get', '/potatos')],\n  [HttpFunctionAdapter.name, createHttpFunctionEvent('get', '')],\n  [\n    HttpFunctionAdapter.name,\n    createHttpFunctionEvent('get', '/query', undefined, undefined, {\n      page: '1',\n    }),\n  ],\n];\n"
  },
  {
    "path": "test/adapters/digital-ocean/utils/http-function.ts",
    "content": "import { type DigitalOceanHttpEvent } from '../../../../src/@types/digital-ocean';\n\nexport function createHttpFunctionEvent(\n  method: string,\n  path: string,\n  body?: Record<string, unknown>,\n  headers?: Record<string, string>,\n  queryParams?: Record<string, string>,\n): DigitalOceanHttpEvent {\n  return {\n    __ow_method: method,\n    __ow_query: new URLSearchParams(queryParams).toString(),\n    __ow_body: JSON.stringify(body),\n    __ow_headers: {\n      accept: '*/*',\n      'accept-encoding': 'gzip',\n      'cdn-loop': 'cloudflare',\n      'cf-connecting-ip': '45.444.444.444',\n      'cf-ipcountry': 'BR',\n      'cf-ray': '4444443444a537-GRU',\n      'cf-visitor': '{\"scheme\":\"https\"}',\n      'content-type': 'application/json',\n      host: 'ccontroller',\n      'user-agent': 'insomnia/2022.4.2',\n      'x-custom': 'potato',\n      'x-forwarded-for': '45.444.444.444',\n      'x-forwarded-proto': 'https',\n      'x-request-id': 'xxxxxxxxxxxxxxxxxx',\n      ...headers,\n    },\n    __ow_path: path,\n    __ow_isBase64Encoded: false,\n  };\n}\n"
  },
  {
    "path": "test/adapters/dummy/dummy.adapter.spec.ts",
    "content": "import { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport {\n  type DelegatedResolver,\n  EmptyResponse,\n  createDefaultLogger,\n} from '../../../src';\nimport { DummyAdapter } from '../../../src/adapters/dummy';\n\ndescribe(DummyAdapter.name, () => {\n  let adapter!: DummyAdapter;\n\n  beforeEach(() => {\n    adapter = new DummyAdapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(DummyAdapter.name);\n    });\n  });\n\n  describe('canHandle', () => {\n    it('should always return true', () => {\n      expect(adapter.canHandle()).toBe(true);\n    });\n  });\n\n  describe('getRequest', () => {\n    it('should always create the same request', () => {\n      const request = adapter.getRequest();\n\n      expect(request).toHaveProperty('body', undefined);\n      expect(request).toHaveProperty('method', 'POST');\n      expect(request).toHaveProperty('path', '/dummy');\n      expect(request.headers).toStrictEqual({});\n    });\n  });\n\n  describe('getResponse', () => {\n    it('should always return empty response', () => {\n      expect(adapter.getResponse()).toBe(EmptyResponse);\n    });\n  });\n\n  describe('onErrorWhileForwarding', () => {\n    it('should always resolve with success', () => {\n      const resolver: DelegatedResolver<void> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      adapter.onErrorWhileForwarding({\n        event: void 0,\n        log: createDefaultLogger(),\n        respondWithErrors: true,\n        error: new Error('test'),\n        delegatedResolver: resolver,\n      });\n\n      expect(resolver.succeed).toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/huawei/huawei-api-gateway.adapter.spec.ts",
    "content": "import { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport {\n  type DelegatedResolver,\n  type GetResponseAdapterProps,\n  type ILogger,\n  getEventBodyAsBuffer,\n  getFlattenedHeadersMap,\n  getPathWithQueryStringParams,\n} from '../../../src';\nimport type {\n  HuaweiApiGatewayEvent,\n  HuaweiApiGatewayResponse,\n} from '../../../src/@types/huawei';\nimport { HuaweiApiGatewayAdapter } from '../../../src/adapters/huawei';\nimport { createCanHandleTestsForAdapter } from '../utils/can-handle';\nimport { createHuaweiApiGateway } from './utils/huawei-api-gateway';\n\ndescribe(HuaweiApiGatewayAdapter.name, () => {\n  let adapter!: HuaweiApiGatewayAdapter;\n\n  beforeEach(() => {\n    adapter = new HuaweiApiGatewayAdapter();\n  });\n\n  describe('getAdapterName', () => {\n    it('should be the same name of the class', () => {\n      expect(adapter.getAdapterName()).toBe(HuaweiApiGatewayAdapter.name);\n    });\n  });\n\n  createCanHandleTestsForAdapter(\n    () => new HuaweiApiGatewayAdapter(),\n    undefined,\n  );\n\n  describe('getRequest', () => {\n    it('should return the correct mapping for the request', () => {\n      const method = 'PUT';\n      const path = '/collaborators';\n      const body = { name: 'H4ad Collaborator' };\n      const queryParams = { page: '44' };\n\n      const event = createHuaweiApiGateway(method, path, body, {}, queryParams);\n      const result = adapter.getRequest(event);\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).toBeInstanceOf(Buffer);\n\n      const [bodyBuffer, contentLength] = getEventBodyAsBuffer(\n        JSON.stringify(body),\n        false,\n      );\n      expect(result.body).toStrictEqual(bodyBuffer);\n      expect(result.headers).toHaveProperty('content-length');\n      expect(result.headers['content-length']).toBe(String(contentLength));\n\n      const remoteAddress = event.headers['x-real-ip'];\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path,\n        event.queryStringParameters,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n\n    it('should return the correct mapping for the request when it has no body', () => {\n      const method = 'GET';\n      const path = '/potatos';\n      const body = undefined;\n\n      const event = createHuaweiApiGateway(method, path, body, undefined, {\n        page: '2',\n      });\n      const result = adapter.getRequest(event);\n\n      const remoteAddress = event.headers['x-real-ip'];\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).not.toBeInstanceOf(Buffer);\n      expect(result.body).toBeUndefined();\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path,\n        event.queryStringParameters,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n\n    it('should return the correct mapping for the request when send stripBasePath', () => {\n      const stripBasePath = '/prod';\n\n      const method = 'GET';\n      const path = '/prod/collaborators';\n      const body = undefined;\n\n      const strippedAdapter = new HuaweiApiGatewayAdapter({ stripBasePath });\n\n      const event = createHuaweiApiGateway(method, path, body);\n      const result = strippedAdapter.getRequest(event);\n\n      const remoteAddress = event.headers['x-real-ip'];\n\n      expect(result).toHaveProperty('method', method);\n      expect(result).toHaveProperty('headers');\n\n      expect(result).toHaveProperty('body');\n      expect(result.body).not.toBeInstanceOf(Buffer);\n      expect(result.body).toBeUndefined();\n\n      expect(result).toHaveProperty('remoteAddress', remoteAddress);\n\n      const resultPath = getPathWithQueryStringParams(\n        path.replace('/prod', ''),\n        event.queryStringParameters,\n      );\n      expect(result).toHaveProperty('path', resultPath);\n    });\n  });\n\n  describe('getResponse', () => {\n    it('should return the correct mapping for the response', () => {\n      const method = 'PUT';\n      const path = '/collaborators';\n      const requestBody = { name: 'H4ad Collaborator V2' };\n      const queryParams = { page: '2' };\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createHuaweiApiGateway(\n        method,\n        path,\n        requestBody,\n        {},\n        queryParams,\n      );\n      const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n      const result = adapter.getResponse({\n        event,\n        log: {} as ILogger,\n        body: resultBody,\n        isBase64Encoded: resultIsBase64Encoded,\n        statusCode: resultStatusCode,\n        headers: {\n          ...resultHeaders,\n        },\n      });\n\n      expect(result).toHaveProperty('statusCode', 200);\n      expect(result).toHaveProperty('body', resultBody);\n      expect(result).toHaveProperty('headers');\n      expect(result).toHaveProperty('isBase64Encoded', resultIsBase64Encoded);\n    });\n\n    it('should return the correct mapping for the response when set-cookie is array', () => {\n      const method = 'PUT';\n      const path = '/collaborators';\n      const requestBody = { name: 'H4ad Collaborator V2' };\n      const queryParams = { page: '2' };\n\n      const resultBody = '{\"success\":true}';\n      const resultStatusCode = 200;\n      const resultIsBase64Encoded = false;\n\n      const event = createHuaweiApiGateway(\n        method,\n        path,\n        requestBody,\n        {},\n        queryParams,\n      );\n      const resultHeaders = getFlattenedHeadersMap(event.headers);\n\n      const result = adapter.getResponse({\n        event,\n        log: {} as ILogger,\n        body: resultBody,\n        isBase64Encoded: resultIsBase64Encoded,\n        statusCode: resultStatusCode,\n        headers: {\n          ...resultHeaders,\n        },\n      });\n\n      expect(result).toHaveProperty('statusCode', 200);\n      expect(result).toHaveProperty('body', resultBody);\n      expect(result).toHaveProperty('headers');\n      expect(result).toHaveProperty('isBase64Encoded', resultIsBase64Encoded);\n    });\n  });\n\n  describe('onErrorWhileForwarding', () => {\n    it('should resolver call succeed', () => {\n      const method = 'GET';\n      const path = '/events';\n      const requestBody = undefined;\n\n      const event = createHuaweiApiGateway(method, path, requestBody);\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<HuaweiApiGatewayResponse> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = true;\n      const error = new Error('Test error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: HuaweiApiGatewayResponse | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<HuaweiApiGatewayEvent>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).toBe(error.stack);\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n\n    it('should resolver call succeed but without sending errors', () => {\n      const method = 'GET';\n      const path = '/users';\n      const requestBody = undefined;\n\n      const event = createHuaweiApiGateway(method, path, requestBody);\n\n      const log = {} as ILogger;\n\n      const resolver: DelegatedResolver<HuaweiApiGatewayResponse> = {\n        fail: vitest.fn(),\n        succeed: vitest.fn(),\n      };\n\n      const respondWithErrors = false;\n      const error = new Error('Test error');\n\n      const oldGetResponse = adapter.getResponse.bind(adapter);\n\n      let getResponseResult: HuaweiApiGatewayResponse | undefined;\n\n      adapter.getResponse = vitest.fn(\n        (params: GetResponseAdapterProps<HuaweiApiGatewayEvent>) => {\n          expect(params.event).toBe(event);\n          expect(params.statusCode).toBe(500);\n          expect(params.body).toBe('');\n          expect(params.isBase64Encoded).toBe(false);\n          expect(params.log).toBe(log);\n          expect(params.headers).toStrictEqual({});\n\n          getResponseResult = oldGetResponse(params);\n\n          return getResponseResult;\n        },\n      );\n\n      adapter.onErrorWhileForwarding({\n        event,\n        log,\n        delegatedResolver: resolver,\n        respondWithErrors,\n        error,\n      });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.getResponse).toHaveBeenCalledTimes(1);\n\n      expect(resolver.fail).toHaveBeenCalledTimes(0);\n      expect(resolver.succeed).toHaveBeenCalledTimes(1);\n\n      expect(resolver.succeed).toHaveBeenCalledWith(getResponseResult);\n    });\n  });\n});\n"
  },
  {
    "path": "test/adapters/huawei/utils/events.ts",
    "content": "import { HuaweiApiGatewayAdapter } from '../../../../src/adapters/huawei';\nimport { createHuaweiApiGateway } from './huawei-api-gateway';\n\nexport const allHuaweiEvents: Array<[string, any]> = [\n  [HuaweiApiGatewayAdapter.name, createHuaweiApiGateway('GET', '/users')],\n  [\n    HuaweiApiGatewayAdapter.name,\n    createHuaweiApiGateway('GET', '/test', undefined, { 'x-batata': 'true' }),\n  ],\n  [HuaweiApiGatewayAdapter.name, createHuaweiApiGateway('DELETE', '/test/2')],\n];\n"
  },
  {
    "path": "test/adapters/huawei/utils/huawei-api-gateway.ts",
    "content": "import type { BothValueHeaders } from '../../../../src';\nimport type {\n  HuaweiApiGatewayEvent,\n  HuaweiRequestQueryStringParameters,\n} from '../../../../src/@types/huawei';\n\nexport function createHuaweiApiGateway(\n  method: string,\n  path: string,\n  body?: object,\n  headers?: BothValueHeaders,\n  queryParams?: HuaweiRequestQueryStringParameters,\n): HuaweiApiGatewayEvent {\n  const bodyBuffer = Buffer.from(JSON.stringify(body || ''), 'utf-8');\n\n  return {\n    body: body ? bodyBuffer.toString('base64') : '',\n    headers: {\n      accept:\n        'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',\n      'accept-encoding': 'gzip, deflate, br',\n      'accept-language': 'pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,bg;q=0.6',\n      'cache-control': 'max-age=0',\n      'content-length': Buffer.byteLength(bodyBuffer).toString(),\n      connection: 'keep-alive',\n      dnt: '1',\n      host: 'test.apig.la-south-2.huaweicloudapis.com',\n      'sec-ch-ua':\n        '\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"101\", \"Google Chrome\";v=\"101\"',\n      'sec-ch-ua-mobile': '?0',\n      'sec-ch-ua-platform': '\"Windows\"',\n      'sec-fetch-dest': 'document',\n      'sec-fetch-mode': 'navigate',\n      'sec-fetch-site': 'none',\n      'sec-fetch-user': '?1',\n      'upgrade-insecure-requests': '1',\n      'user-agent':\n        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',\n      'x-forwarded-for': '33.33.33.33',\n      'x-forwarded-host': 'test.apig.la-south-2.huaweicloudapis.com',\n      'x-forwarded-port': '443',\n      'x-forwarded-proto': 'https',\n      'x-real-ip': '33.33.33.33',\n      'x-request-id': 'eb6f50b5922fd574175f8115ba22c168',\n      ...headers,\n    },\n    httpMethod: method,\n    isBase64Encoded: true,\n    'lubanops-gtrace-id': '',\n    'lubanops-ndomain-id': '',\n    'lubanops-nenv-id': '',\n    'lubanops-nspan-id': '',\n    'lubanops-ntrace-id': '',\n    'lubanops-sevent-id': '',\n    path,\n    pathParameters: {},\n    queryStringParameters: {\n      ...queryParams,\n    },\n    requestContext: {\n      apiId: '863aad9dd5dd4043b7f6745b34922323',\n      requestId: 'eb6f50b5922fd574175f8115ba943222',\n      stage: 'RELEASE',\n    },\n  };\n}\n"
  },
  {
    "path": "test/adapters/test.example",
    "content": "describe(Adapter.name, () => {\r\n  let adapter!: Adapter;\r\n\r\n  beforeEach(() => {\r\n    adapter = new Adapter();\r\n  });\r\n\r\n  describe('getAdapterName', () => {\r\n    it('should be the same name of the class', () => {\r\n      expect(adapter.getAdapterName()).toBe(Adapter.name);\r\n    });\r\n  });\r\n\r\n  createCanHandleTestsForAdapter(() => new Adapter(), undefined);\r\n\r\n  describe('getRequest', () => {\r\n    it('should return the correct mapping for the request', () => {\r\n      const method = 'PUT';\r\n      const path = '/events';\r\n      const body = { name: 'H4ad Event' };\r\n    });\r\n  });\r\n\r\n  describe('getResponse', () => {\r\n    it('should return the correct mapping for the response', () => {\r\n      const method = 'PUT';\r\n      const path = '/events';\r\n      const requestBody = { name: 'H4ad Event' };\r\n\r\n      const resultBody = '{\"success\":true}';\r\n      const resultStatusCode = 200;\r\n      const resultIsBase64Encoded = false;\r\n    });\r\n  });\r\n\r\n  describe('onErrorWhileForwarding', () => {\r\n    it('should resolver call succeed', () => {\r\n      const method = 'GET';\r\n      const path = '/events';\r\n      const requestBody = undefined;\r\n    });\r\n  });\r\n});\r\n"
  },
  {
    "path": "test/adapters/utils/can-handle.ts",
    "content": "import { beforeEach, describe, expect, it } from 'vitest';\nimport type { AdapterContract, ILogger } from '../../../src';\nimport { allEvents } from './events';\n\nexport function createCanHandleTestsForAdapter<\n  T,\n  TContext = any,\n  TResponse = any,\n>(\n  adapterFactory: () => AdapterContract<T, TContext, TResponse>,\n  context: TContext,\n  logger: ILogger = {} as ILogger,\n): void {\n  let adapter!: AdapterContract<T, TContext, TResponse>;\n\n  beforeEach(() => {\n    adapter = adapterFactory();\n  });\n\n  describe('canHandle', () => {\n    it('should return true when is valid event', () => {\n      const events = allEvents.filter(\n        ([adapterName]) => adapterName === adapter.getAdapterName(),\n      )!;\n\n      expect(events.length).toBeGreaterThan(0);\n\n      for (const [, event] of events)\n        expect(adapter.canHandle(event, context, logger)).toBe(true);\n    });\n\n    it('should return false when is not a valid event', () => {\n      const events = allEvents.filter(\n        ([adapterName]) => adapterName !== adapter.getAdapterName(),\n      );\n\n      expect(events.length).toBeGreaterThan(0);\n\n      for (const [adapterName, event] of events) {\n        const canHandle = adapter.canHandle(event, context, logger);\n\n        expect(`${adapterName}: ${canHandle}`).toEqual(`${adapterName}: false`);\n      }\n    });\n  });\n}\n"
  },
  {
    "path": "test/adapters/utils/events.ts",
    "content": "import { allAWSEvents } from '../aws/utils/events';\nimport { allAzureEvents } from '../azure/utils/events';\nimport { allDigitalOceanEvents } from '../digital-ocean/utils/event';\nimport { allHuaweiEvents } from '../huawei/utils/events';\n\n/**\n * Events from all event sources that can be used to test adapters\n */\nexport const allEvents: [string, any][] = [\n  ...allAWSEvents,\n  ...allHuaweiEvents,\n  ...allAzureEvents,\n  ...allDigitalOceanEvents,\n];\n"
  },
  {
    "path": "test/core/base-handler.spec.ts",
    "content": "import { describe, expect, it, vitest } from 'vitest';\nimport {\n  type AdapterContract,\n  type AdapterRequest,\n  BaseHandler,\n  type ILogger,\n  ServerlessRequest,\n  ServerlessResponse,\n  createDefaultLogger,\n} from '../../src';\nimport { AlbAdapter, SQSAdapter } from '../../src/adapters/aws';\nimport { createSQSEvent } from '../adapters/aws/utils/sqs';\n\nclass TestHandler<TApp, TContext, TCallback, TReturn> extends BaseHandler<\n  TApp,\n  unknown,\n  TContext,\n  TCallback,\n  unknown,\n  TReturn\n> {\n  getHandler = vitest.fn();\n\n  /**\n   * {@inheritDoc}\n   */\n  public override getAdapterByEventAndContext(\n    event: any,\n    context: any,\n    adapters: AdapterContract<unknown, TContext, unknown>[],\n    log: ILogger,\n  ): AdapterContract<unknown, TContext, unknown> {\n    return super.getAdapterByEventAndContext(event, context, adapters, log);\n  }\n\n  /**\n   * {@inheritDoc}\n   */\n  public override getServerlessRequestResponseFromAdapterRequest(\n    requestValues: AdapterRequest,\n  ): [request: ServerlessRequest, response: ServerlessResponse] {\n    return super.getServerlessRequestResponseFromAdapterRequest(requestValues);\n  }\n}\n\ndescribe(BaseHandler.name, () => {\n  it('should can resolve adapter by event and context', () => {\n    const handler = new TestHandler();\n    const testEvent = createSQSEvent();\n    const eventAdapter = new SQSAdapter();\n    const adapters = [eventAdapter, new AlbAdapter()] as AdapterContract<\n      any,\n      any,\n      any\n    >[];\n    const context = {};\n    const logger = createDefaultLogger();\n\n    adapters.forEach(adapter => {\n      // @ts-ignore\n      adapter.canHandle = vitest.fn(adapter.canHandle.bind(adapter));\n    });\n\n    expect(\n      handler.getAdapterByEventAndContext(testEvent, context, adapters, logger),\n    ).toBe(eventAdapter);\n\n    adapters.forEach(adapter => {\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(adapter.canHandle).toHaveBeenCalledWith(\n        testEvent,\n        context,\n        logger,\n      );\n    });\n  });\n\n  it('should throw error when could not resolve the adapter', () => {\n    const handler = new TestHandler();\n    const testEvent = {};\n    const adapters = [];\n\n    expect(() =>\n      handler.getAdapterByEventAndContext(\n        testEvent,\n        {},\n        adapters,\n        createDefaultLogger(),\n      ),\n    ).toThrowError(\"Couldn't find adapter\");\n  });\n\n  it('should throw error when resolve more than one adapter', () => {\n    const handler = new TestHandler();\n    const testEvent = createSQSEvent();\n    const adapters = [new SQSAdapter(), new SQSAdapter()] as AdapterContract<\n      any,\n      any,\n      any\n    >[];\n    const adapterNames = adapters\n      .map(adapter => adapter.getAdapterName())\n      .join(', ');\n\n    expect(() =>\n      handler.getAdapterByEventAndContext(\n        testEvent,\n        {},\n        adapters,\n        createDefaultLogger(),\n      ),\n    ).toThrowError(adapterNames);\n  });\n\n  it('should can create correctly request and response from adapter request', () => {\n    const handler = new TestHandler();\n\n    const testEvent = createSQSEvent();\n    const adapter = new SQSAdapter({\n      sqsForwardPath: '/sqs',\n      sqsForwardMethod: 'POST',\n    });\n\n    const adapterRequest = adapter.getRequest(testEvent);\n\n    const [request, response] =\n      handler.getServerlessRequestResponseFromAdapterRequest(adapterRequest);\n\n    expect(request).toBeInstanceOf(ServerlessRequest);\n    expect(request).toHaveProperty('method', adapterRequest.method);\n    expect(request).toHaveProperty('url', adapterRequest.path);\n    expect(request).toHaveProperty('headers', adapterRequest.headers);\n    expect(request).toHaveProperty('body', adapterRequest.body);\n    expect(request.socket).toHaveProperty(\n      'remoteAddress',\n      adapterRequest.remoteAddress,\n    );\n\n    expect(response).toBeInstanceOf(ServerlessResponse);\n  });\n});\n"
  },
  {
    "path": "test/core/current-invoke.spec.ts",
    "content": "import { describe, expect, it } from 'vitest';\nimport { getCurrentInvoke, setCurrentInvoke } from '../../src';\n\ndescribe('CurrentInvoke', () => {\n  it('should initial values of getCurrentInvoke be null', () => {\n    const initial = getCurrentInvoke();\n\n    expect(initial).toBeDefined();\n\n    expect(initial).toHaveProperty('event', null);\n    expect(initial).toHaveProperty('context', null);\n  });\n\n  it('should set and get current invoke without problems', () => {\n    const event = { batata: true };\n    const context = { potato: true };\n\n    expect(() => setCurrentInvoke({ event, context })).not.toThrowError();\n\n    const currentInvoke = getCurrentInvoke();\n\n    expect(currentInvoke).toHaveProperty('event', event);\n    expect(currentInvoke).toHaveProperty('context', context);\n  });\n});\n"
  },
  {
    "path": "test/core/event-body.spec.ts",
    "content": "import { describe, expect, it } from 'vitest';\nimport { getEventBodyAsBuffer } from '../../src';\n\ndescribe('getEventBodyAsBuffer', () => {\n  it('should return correctly the body in utf-8 as buffer', () => {\n    const body = '{}';\n\n    const [bodyAsBuffer, contentLength] = getEventBodyAsBuffer(body, false);\n\n    expect(bodyAsBuffer).toBeInstanceOf(Buffer);\n    expect(contentLength).toBe(2);\n\n    expect(bodyAsBuffer.toString('utf8')).toBe(body);\n  });\n\n  it('should return correctly the body in base64 as buffer', () => {\n    const body = Buffer.from('{}', 'utf8').toString('base64');\n\n    const [bodyAsBuffer, contentLength] = getEventBodyAsBuffer(body, true);\n\n    expect(bodyAsBuffer).toBeInstanceOf(Buffer);\n    expect(contentLength).toBe(2);\n\n    expect(bodyAsBuffer.toString('base64')).toBe(body);\n  });\n});\n"
  },
  {
    "path": "test/core/headers.spec.ts",
    "content": "import { describe, expect, it } from 'vitest';\nimport {\n  type BothValueHeaders,\n  getFlattenedHeadersMap,\n  getFlattenedHeadersMapAndCookies,\n  getMultiValueHeadersMap,\n} from '../../src';\n\ndescribe('getFlattenedHeadersMap', () => {\n  it('should return headers flattened', () => {\n    const headerLists: BothValueHeaders[] = [\n      {\n        'Accept-Encoding': 'gzip',\n        'Accept-Language': 'en-US,en;q=0.9',\n        Host: undefined,\n        'Content-Type': '',\n        'Content-Length': 40 as unknown as string,\n      },\n      {\n        'Accept-Encoding': ['gzip'],\n        'Accept-Language': ['en-US', 'en;q=0.9'],\n        Host: undefined,\n        'Content-Type': '',\n        'Content-Length': [40] as unknown as string[],\n      },\n    ];\n\n    for (const headers of headerLists) {\n      const flattenedHeaders = getFlattenedHeadersMap(headers);\n\n      expect(Object.keys(flattenedHeaders).length).toEqual(\n        Object.keys(headers).length,\n      );\n\n      expect(flattenedHeaders).toHaveProperty('Accept-Encoding');\n      expect(flattenedHeaders['Accept-Encoding']).toEqual('gzip');\n      expect(flattenedHeaders['Accept-Language']).toEqual('en-US,en;q=0.9');\n      expect(flattenedHeaders['Content-Length']).toEqual('40');\n    }\n  });\n\n  it('should return headers flattened with custom options', () => {\n    const defaultSingleValueHeaders = {\n      'Accept-Encoding': 'gzip',\n      'Accept-Language': 'en-US,en;q=0.9',\n    };\n    const defaultMultiValueHeaders = {\n      'Accept-Encoding': ['gzip'],\n      'Accept-Language': ['en-US', 'en;q=0.9'],\n    };\n\n    const headerLists: [\n      headers: BothValueHeaders,\n      separator: string,\n      lowerCase: boolean,\n    ][] = [\n      [defaultSingleValueHeaders, ',', false],\n      [defaultMultiValueHeaders, ',', false],\n      [defaultSingleValueHeaders, '|', false],\n      [defaultMultiValueHeaders, '|', false],\n      [defaultSingleValueHeaders, ',', true],\n      [defaultMultiValueHeaders, ',', true],\n      [defaultSingleValueHeaders, '|', true],\n      [defaultMultiValueHeaders, '|', true],\n    ];\n\n    for (const [headers, separator, lowerCase] of headerLists) {\n      const flattenedHeaders = getFlattenedHeadersMap(\n        headers,\n        separator,\n        lowerCase,\n      );\n\n      expect(Object.keys(flattenedHeaders).length).toEqual(\n        Object.keys(headers).length,\n      );\n\n      const checkedHeader = lowerCase ? 'accept-encoding' : 'Accept-Encoding';\n\n      const arrayCheckedHeader = lowerCase\n        ? 'accept-language'\n        : 'Accept-Language';\n\n      expect(flattenedHeaders).toHaveProperty(checkedHeader);\n      expect(flattenedHeaders[checkedHeader]).toEqual('gzip');\n\n      if (Array.isArray(headers['Accept-Language'])) {\n        expect(headers['Accept-Language']).toStrictEqual(\n          flattenedHeaders[arrayCheckedHeader].split(separator),\n        );\n      } else {\n        expect(headers['Accept-Language']).toStrictEqual(\n          flattenedHeaders[arrayCheckedHeader],\n        );\n      }\n    }\n  });\n});\n\ndescribe('getMultiValueHeadersMap', () => {\n  it('should return headers flattened', () => {\n    const headerLists: BothValueHeaders[] = [\n      {\n        'Accept-Encoding': 'gzip',\n        'Accept-Language': 'en-US,en;q=0.9',\n        Host: undefined,\n        'Content-Type': '',\n      },\n      {\n        'Accept-Encoding': ['gzip'],\n        'Accept-Language': ['en-US', 'en;q=0.9'],\n        Host: undefined,\n        'Content-Type': '',\n      },\n    ];\n\n    for (const headers of headerLists) {\n      const multiValueHeadersMap = getMultiValueHeadersMap(headers);\n\n      expect(Object.keys(multiValueHeadersMap).length).toEqual(\n        Object.keys(headers).length,\n      );\n\n      expect(multiValueHeadersMap).toHaveProperty('accept-encoding', ['gzip']);\n      expect(\n        Object.keys(multiValueHeadersMap).every(key =>\n          Array.isArray(multiValueHeadersMap[key]),\n        ),\n      );\n    }\n  });\n});\n\ndescribe('getFlattenedHeadersMapAndCookies', () => {\n  it('should return headers flattened', () => {\n    const headerLists: BothValueHeaders[] = [\n      {\n        'Accept-Encoding': 'gzip',\n        'Accept-Language': 'en-US,en;q=0.9',\n        Host: undefined,\n        'Content-Type': '',\n        'Content-Length': 40 as unknown as string,\n        'Set-Cookie': 'blabla',\n      },\n      {\n        'Accept-Encoding': ['gzip'],\n        'Accept-Language': ['en-US', 'en;q=0.9'],\n        Host: undefined,\n        'Content-Type': '',\n        'Content-Length': [40] as unknown as string[],\n        'Set-Cookie': ['blabla'],\n      },\n    ];\n\n    for (const headers of headerLists) {\n      const { headers: flattenedHeaders, cookies } =\n        getFlattenedHeadersMapAndCookies(headers);\n\n      expect(Object.keys(flattenedHeaders).length).toEqual(\n        Object.keys(headers).length - 1,\n      );\n\n      expect(flattenedHeaders).toHaveProperty('Accept-Encoding');\n      expect(flattenedHeaders['Accept-Encoding']).toEqual('gzip');\n      expect(flattenedHeaders['Accept-Language']).toEqual('en-US,en;q=0.9');\n      expect(flattenedHeaders['Content-Length']).toEqual('40');\n      expect(flattenedHeaders['Content-Length']).toEqual('40');\n      expect(cookies[0]).toEqual('blabla');\n    }\n  });\n});\n"
  },
  {
    "path": "test/core/is-binary.spec.ts",
    "content": "import { describe, expect, it } from 'vitest';\nimport {\n  type BothValueHeaders,\n  DEFAULT_BINARY_CONTENT_TYPES,\n  DEFAULT_BINARY_ENCODINGS,\n  getContentType,\n  isBinary,\n  isContentEncodingBinary,\n  isContentTypeBinary,\n} from '../../src';\n\ntype HeaderListJest = [headers: BothValueHeaders, expectedValue: boolean][];\n\nconst headerListForContentEncodings: HeaderListJest = [\n  [{ 'content-encoding': undefined }, false],\n  [{ 'content-encoding': [] }, false],\n  [{ 'content-encoding': 'non-standard' }, false],\n  [{ 'content-encoding': ['non-standard'] }, false],\n  [{ 'content-encoding': 'gzip' }, true],\n  [{ 'content-encoding': 'deflate' }, true],\n  [{ 'content-encoding': 'br' }, true],\n  [{ 'content-encoding': 'gzip,non-standard' }, true],\n  [{ 'content-encoding': ['gzip'] }, true],\n  [{ 'content-encoding': ['gzip', 'non-standard'] }, true],\n  [{ 'content-encoding': ['deflate'] }, true],\n  [{ 'content-encoding': ['deflate', 'non-standard'] }, true],\n  [{ 'content-encoding': ['br'] }, true],\n  [{ 'content-encoding': ['br', 'non-standard'] }, true],\n];\n\nconst headerListForContentTypes: HeaderListJest = [\n  [{ 'content-type': undefined }, false],\n  [{ 'content-type': [] }, false],\n  [{ 'content-type': 'application/json' }, false],\n  [{ 'content-type': ['application/json'] }, false],\n  [{ 'content-type': 'application/json,image/png' }, false],\n  [{ 'content-type': 'application/json;image/png' }, false],\n  [{ 'content-type': ['application/json', 'image/png'] }, false],\n  [{ 'content-type': 'image/png' }, true],\n  [{ 'content-type': ['image/png'] }, true],\n  [{ 'content-type': 'video/mp4' }, true],\n  [{ 'content-type': ['video/mp4'] }, true],\n  [{ 'content-type': 'application/pdf' }, true],\n  [{ 'content-type': ['application/pdf'] }, true],\n];\n\ndescribe('isContentEncodingBinary', () => {\n  it('should correctly check if content encoding is binary', () => {\n    const headersList: HeaderListJest = [\n      [{ 'content-type': 'application/json' }, false],\n      ...headerListForContentEncodings,\n    ];\n\n    const binaryEncodings = DEFAULT_BINARY_ENCODINGS;\n\n    for (const [headers, expectedValue] of headersList) {\n      const isBinary = isContentEncodingBinary(headers, binaryEncodings);\n\n      expect(isBinary).toBe(expectedValue);\n    }\n  });\n});\n\ndescribe('getContentType', () => {\n  it('should correctly return the content type from headers', () => {\n    const headersList: [headers: BothValueHeaders, expectedValue: string][] = [\n      [{ 'content-encoding': 'gzip' }, ''],\n      [{ 'content-type': 'application/json' }, 'application/json'],\n      [{ 'content-type': ['application/json'] }, 'application/json'],\n      [\n        { 'content-type': 'application/json,image/png' },\n        'application/json,image/png',\n      ],\n      [{ 'content-type': 'application/json;image/png' }, 'application/json'],\n      [\n        { 'content-type': ['application/json', 'image/png'] },\n        'application/json',\n      ],\n      [{ 'content-type': ['image/png', 'application/json'] }, 'image/png'],\n    ];\n\n    for (const [headers, expectedValue] of headersList) {\n      const isBinary = getContentType(headers);\n\n      expect(isBinary).toBe(expectedValue);\n    }\n  });\n});\n\ndescribe('isContentTypeBinary', () => {\n  it('should correctly check if content type is binary', () => {\n    const headersList: [headers: BothValueHeaders, expectedValue: boolean][] = [\n      [{ 'content-encoding': 'gzip' }, false],\n      ...headerListForContentTypes,\n    ];\n\n    const binaryEncodings = DEFAULT_BINARY_CONTENT_TYPES;\n\n    for (const [headers, expectedValue] of headersList) {\n      const isBinary = isContentTypeBinary(headers, binaryEncodings);\n\n      expect(isBinary).toBe(expectedValue);\n    }\n  });\n});\n\ndescribe('isBinary', () => {\n  it('should correctly return if content is binary', () => {\n    const headersList: [headers: BothValueHeaders, expectedValue: boolean][] = [\n      [{ Host: 'blablabla.com' }, false],\n      ...headerListForContentEncodings,\n      ...headerListForContentTypes,\n    ];\n\n    const contentTypes = DEFAULT_BINARY_CONTENT_TYPES;\n    const contentEncodings = DEFAULT_BINARY_ENCODINGS;\n\n    for (const [headers, expectedValue] of headersList) {\n      const isContentBinary = isBinary(headers, {\n        contentTypes,\n        contentEncodings,\n      });\n\n      expect(\n        isContentBinary,\n        `contentTypes: ${contentTypes.join(\n          ';',\n        )}, contentEncodings: ${contentEncodings.join(\n          ';',\n        )}: has ${expectedValue} inside ${JSON.stringify(headers)}`,\n      ).toBe(expectedValue);\n    }\n  });\n\n  it('should correctly return if content is binary with custom \"isBinary\" option', () => {\n    const headersList: [headers: BothValueHeaders, expectedValue: boolean][] = [\n      [{ Host: 'blablabla.com' }, false],\n      ...headerListForContentEncodings,\n      ...headerListForContentTypes,\n    ];\n\n    for (const [headers] of headersList) {\n      const isContentBinary = isBinary(headers, {\n        isBinary: () => true,\n      });\n\n      expect(isContentBinary).toBe(true);\n    }\n\n    for (const [headers] of headersList) {\n      const isContentBinary = isBinary(headers, {\n        isBinary: false,\n      });\n\n      expect(isContentBinary).toBe(false);\n    }\n  });\n});\n"
  },
  {
    "path": "test/core/logger.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n\nimport {\n  type MockInstance,\n  afterEach,\n  beforeEach,\n  describe,\n  expect,\n  it,\n  vitest,\n} from 'vitest';\nimport {\n  type LogLevels,\n  NO_OP,\n  createDefaultLogger,\n  isInternalLogger,\n} from '../../src';\n\ndescribe('createDefaultLogger', () => {\n  const mocks: MockInstance[] = [];\n\n  beforeEach(() => {\n    const mockMethods: (keyof Console)[] = [\n      'error',\n      'info',\n      'warn',\n      'log',\n      'debug',\n    ];\n\n    for (const method of mockMethods) {\n      mocks.push(\n        vitest.spyOn(global.console, method).mockImplementation(NO_OP),\n      );\n    }\n  });\n\n  afterEach(() => {\n    for (const mock of mocks) mock.mockRestore();\n  });\n\n  it('should create correctly the logger instance', () => {\n    expect(createDefaultLogger()).toBeDefined();\n  });\n\n  it('should lazy log when we pass a function', () => {\n    const logger = createDefaultLogger({ level: 'debug' });\n\n    logger.debug('debug', () => '=true', ' works');\n\n    expect(global.console.debug).not.toHaveBeenNthCalledWith(\n      1,\n      'debug=true works',\n    );\n  });\n\n  it('should log correctly with log level as none', () => {\n    const logger = createDefaultLogger({ level: 'none' });\n\n    logger.error('error');\n    logger.warn('warn');\n    logger.info('info');\n    logger.verbose('verbose');\n    logger.debug('debug');\n\n    expect(global.console.error).not.toHaveBeenCalledWith('error');\n    expect(global.console.warn).not.toHaveBeenCalledWith('warn');\n    expect(global.console.info).not.toHaveBeenCalledWith('info');\n    expect(global.console.debug).not.toHaveBeenNthCalledWith(1, 'verbose');\n    expect(global.console.debug).not.toHaveBeenNthCalledWith(2, 'debug');\n  });\n\n  it('should log correctly with log level as error', () => {\n    const logger = createDefaultLogger({ level: 'error' });\n\n    logger.error('error');\n    logger.warn('warn');\n    logger.info('info');\n    logger.verbose('verbose');\n    logger.debug('debug');\n\n    expect(global.console.error).toHaveBeenCalledWith('error');\n    expect(global.console.warn).not.toHaveBeenCalledWith('warn');\n    expect(global.console.info).not.toHaveBeenCalledWith('info');\n    expect(global.console.debug).not.toHaveBeenNthCalledWith(1, 'verbose');\n    expect(global.console.debug).not.toHaveBeenNthCalledWith(2, 'debug');\n  });\n\n  it('should log correctly with log level as warn', () => {\n    const logger = createDefaultLogger({ level: 'warn' });\n\n    logger.error('error');\n    logger.warn('warn');\n    logger.info('info');\n    logger.verbose('verbose');\n    logger.debug('debug');\n\n    expect(global.console.error).toHaveBeenCalledWith('error');\n    expect(global.console.warn).toHaveBeenCalledWith('warn');\n    expect(global.console.info).not.toHaveBeenCalledWith('info');\n    expect(global.console.debug).not.toHaveBeenNthCalledWith(1, 'verbose');\n    expect(global.console.debug).not.toHaveBeenNthCalledWith(2, 'debug');\n  });\n\n  it('should log correctly with log level as info', () => {\n    const logger = createDefaultLogger({ level: 'info' });\n\n    logger.error('error');\n    logger.warn('warn');\n    logger.info('info');\n    logger.verbose('verbose');\n    logger.debug('debug');\n\n    expect(global.console.error).toHaveBeenCalledWith('error');\n    expect(global.console.warn).toHaveBeenCalledWith('warn');\n    expect(global.console.info).toHaveBeenCalledWith('info');\n    expect(global.console.debug).not.toHaveBeenNthCalledWith(1, 'verbose');\n    expect(global.console.debug).not.toHaveBeenNthCalledWith(2, 'debug');\n  });\n\n  it('should log correctly with log level as verbose', () => {\n    const logger = createDefaultLogger({ level: 'verbose' });\n\n    logger.error('error');\n    logger.warn('warn');\n    logger.info('info');\n    logger.verbose('verbose');\n    logger.debug('debug');\n\n    expect(global.console.error).toHaveBeenCalledWith('error');\n    expect(global.console.warn).toHaveBeenCalledWith('warn');\n    expect(global.console.info).toHaveBeenCalledWith('info');\n    expect(global.console.debug).toHaveBeenNthCalledWith(1, 'verbose');\n    expect(global.console.debug).not.toHaveBeenNthCalledWith(2, 'debug');\n  });\n\n  it('should log correctly with log level as debug', () => {\n    const logger = createDefaultLogger({ level: 'debug' });\n\n    logger.error('error');\n    logger.warn('warn');\n    logger.info('info');\n    logger.verbose('verbose');\n    logger.debug('debug');\n\n    expect(global.console.error).toHaveBeenCalledWith('error');\n    expect(global.console.warn).toHaveBeenCalledWith('warn');\n    expect(global.console.info).toHaveBeenCalledWith('info');\n    expect(global.console.debug).toHaveBeenNthCalledWith(1, 'verbose');\n    expect(global.console.debug).toHaveBeenNthCalledWith(2, 'debug');\n  });\n\n  it('should throw error with invalid log level', () => {\n    expect(() =>\n      createDefaultLogger({ level: 'random' as unknown as LogLevels }),\n    ).toThrowError('Invalid');\n  });\n});\n\ndescribe('isInternalLogger', () => {\n  const logLevelRecord: Record<Exclude<LogLevels, 'none'>, true> = {\n    debug: true,\n    info: true,\n    verbose: true,\n    warn: true,\n    error: true,\n  };\n\n  const logLevels = Object.keys(logLevelRecord) as LogLevels[];\n\n  for (const logLevel of logLevels) {\n    it(`instance created by createDefaultLogger with logLevel: ${logLevel} should return true`, () => {\n      const logger = createDefaultLogger({\n        level: logLevel,\n      });\n\n      expect(isInternalLogger(logger)).toBe(true);\n    });\n  }\n\n  it('random instance of ILogger should not return true', () => {\n    expect(\n      isInternalLogger({\n        debug: NO_OP,\n        info: NO_OP,\n        verbose: NO_OP,\n        warn: NO_OP,\n        error: NO_OP,\n      }),\n    ).toBe(false);\n  });\n});\n"
  },
  {
    "path": "test/core/no-op.spec.ts",
    "content": "import { describe, expect, it } from 'vitest';\nimport { NO_OP } from '../../src';\n\ndescribe('NO_OP', () => {\n  it('should be a function', () => {\n    expect(NO_OP).toBeInstanceOf(Function);\n  });\n\n  it('should be callable and return undefined', () => {\n    expect(() => NO_OP()).not.toThrowError();\n\n    expect(NO_OP()).toBe(undefined);\n  });\n});\n"
  },
  {
    "path": "test/core/optional.spec.ts",
    "content": "import { describe, expect, it } from 'vitest';\nimport { getDefaultIfUndefined } from '../../src';\n\ndescribe('getDefaultIfUndefined', () => {\n  it('should return the value when value is not undefined', () => {\n    const options: [testValue: any, defaultValue: any, expectedValue: any][] = [\n      ['batata', 'potato', 'batata'],\n      [true, false, true],\n      [false, true, false],\n    ];\n\n    for (const [testValue, defaultValue, expectedValue] of options) {\n      expect(getDefaultIfUndefined(testValue, defaultValue)).toBe(\n        expectedValue,\n      );\n    }\n  });\n\n  it('should return the default value when value is undefined', () => {\n    const options: [testValue: any, defaultValue: any, expectedValue: any][] = [\n      [undefined, true, true],\n      [undefined, 'text', 'text'],\n      [void 0, true, true],\n      [void 0, 'text', 'text'],\n    ];\n\n    for (const [testValue, defaultValue, expectedValue] of options) {\n      expect(getDefaultIfUndefined(testValue, defaultValue)).toBe(\n        expectedValue,\n      );\n    }\n  });\n});\n"
  },
  {
    "path": "test/core/path.spec.ts",
    "content": "import { describe, expect, it } from 'vitest';\nimport {\n  buildStripBasePath,\n  getPathWithQueryStringParams,\n  getQueryParamsStringFromRecord,\n} from '../../src';\n\ndescribe('getPathWithQueryStringParams', () => {\n  it('should correctly return path and query string concaneted', () => {\n    const options: [\n      path: string,\n      queryParams:\n        | string\n        | Record<string, string | string[] | undefined>\n        | undefined\n        | null,\n      expectedValue: string,\n    ][] = [\n      ['/users', undefined, '/users'],\n      ['/users', null, '/users'],\n      ['/users', 'limit=100', '/users?limit=100'],\n      ['/users', {}, '/users'],\n      ['/users', { page: '1' }, '/users?page=1'],\n      ['/users', { page: '1', limit: '100' }, '/users?page=1&limit=100'],\n      [\n        '/users',\n        { page: '1', limit: '100', s: undefined },\n        '/users?page=1&limit=100&s=',\n      ],\n      ['/users', { joins: ['details'] }, '/users?joins=details'],\n      [\n        '/users',\n        { joins: ['details', 'address'] },\n        '/users?joins=details&joins=address',\n      ],\n      [\n        '/users',\n        {\n          page: '1',\n          limit: '100',\n          s: undefined,\n          joins: ['details', 'address'],\n        },\n        '/users?page=1&limit=100&s=&joins=details&joins=address',\n      ],\n    ];\n\n    for (const [path, queryParams, expectedValue] of options) {\n      expect(getPathWithQueryStringParams(path, queryParams)).toBe(\n        expectedValue,\n      );\n    }\n  });\n});\n\ndescribe('getQueryParamsStringFromRecord', () => {\n  it('should correctly return query string from values', () => {\n    const options: [\n      queryParams:\n        | Record<string, string | string[] | undefined>\n        | undefined\n        | null,\n      expectedValue: string,\n    ][] = [\n      [undefined, ''],\n      [null, ''],\n      [{ page: '1' }, 'page=1'],\n      [{ page: '1', limit: '100' }, 'page=1&limit=100'],\n      [{ page: '1', limit: '100', s: undefined }, 'page=1&limit=100&s='],\n      [{ joins: ['details'] }, 'joins=details'],\n      [{ joins: ['details', 'address'] }, 'joins=details&joins=address'],\n      [\n        {\n          page: '1',\n          limit: '100',\n          s: undefined,\n          joins: ['details', 'address'],\n        },\n        'page=1&limit=100&s=&joins=details&joins=address',\n      ],\n    ];\n\n    for (const [queryParams, expectedValue] of options)\n      expect(getQueryParamsStringFromRecord(queryParams)).toBe(expectedValue);\n  });\n});\n\ndescribe('buildStripBasePath', () => {\n  it('should correctly return query string from values', () => {\n    const options: [\n      basePath: string | undefined,\n      path: string,\n      expectedValue: string,\n    ][] = [\n      ['/prod', '/prod/users', '/users'],\n      ['/v1', '/v1/potato', '/potato'],\n      ['', '/v1/users', '/v1/users'],\n      [undefined, '/v1/courses', '/v1/courses'],\n      ['/prod', '/prod', '/'],\n      ['/prod', '/ignore-path', '/ignore-path'],\n      ['/v1', '/prod/v1/ignore-path', '/prod/v1/ignore-path'],\n    ];\n\n    for (const [basePath, path, expectedValue] of options)\n      expect(buildStripBasePath(basePath)(path)).toBe(expectedValue);\n  });\n});\n"
  },
  {
    "path": "test/core/stream.spec.ts",
    "content": "import { ObjectReadableMock, ObjectWritableMock } from 'stream-mock';\nimport { describe, expect, it } from 'vitest';\nimport { NO_OP, waitForStreamComplete } from '../../src';\nimport ErrorReadableMock from './utils/stream';\n\ndescribe('waitForStreamComplete', () => {\n  it('should wait for the writable stream to complete', async () => {\n    const testedData = 'test';\n\n    const read = new ObjectReadableMock(testedData);\n    const writer = new ObjectWritableMock();\n\n    read.pipe(writer);\n\n    const waitedStream = await waitForStreamComplete(writer);\n\n    expect(waitedStream).toBe(writer);\n    expect(writer.data.join('')).toBe(testedData);\n\n    const waitedStream2 = await waitForStreamComplete(writer);\n\n    expect(waitedStream2).toBe(writer);\n    expect(writer.data.join('')).toBe(testedData);\n  });\n\n  it('should wait for the readable stream to complete', async () => {\n    const testedData: number[] = [0, 1, 2, 3, 4];\n\n    const read = new ObjectReadableMock(testedData);\n    const resultData: number[] = [];\n\n    read.on('data', value => resultData.push(value));\n\n    const waitedStream = await waitForStreamComplete(read);\n\n    expect(waitedStream).toBe(read);\n    expect(resultData).toStrictEqual(testedData);\n\n    const waitedStream2 = await waitForStreamComplete(read);\n\n    expect(waitedStream2).toBe(read);\n    expect(resultData).toStrictEqual(testedData);\n  });\n\n  it('should throw error when error occours', async () => {\n    const error = new Error('error on read');\n\n    const read = new ErrorReadableMock(error, { objectMode: true });\n\n    read.on('data', NO_OP);\n\n    await expect(waitForStreamComplete(read)).rejects.toThrowError(error);\n  });\n\n  it('should handle correctly if events emit end and finish', async () => {\n    const testedData: number[] = [0, 1, 2, 3, 4];\n    const read = new ObjectReadableMock(testedData);\n\n    setTimeout(() => {\n      read.pause();\n\n      read.emit('error');\n      read.emit('end');\n      read.emit('finish');\n\n      read.resume();\n    }, 100);\n\n    await expect(waitForStreamComplete(read)).resolves.not.toThrowError();\n  });\n});\n"
  },
  {
    "path": "test/core/utils/stream.ts",
    "content": "// credits to: https://github.com/b4nst/stream-mock/pull/64/files#diff-52aee274967f2fcfa3ffa78ebba2f510dd23d176aa92ccf8c0ad4843373f5ce7\n\nimport { Readable, type ReadableOptions } from 'node:stream';\nimport type { IReadableMock } from 'stream-mock';\n\n/**\n * ErrorReadableMock is a readable stream that mocks error.\n *\n * @example\n * ```typescript\n * import { ErrorReadableMock } from 'stream-mock';\n *\n * const reader = new ErrorReadble(new Error(\"mock error\"));\n * reader.on(\"data\", () => console.log('not called'));\n * reader.on(\"error\", e => console.log('called'));\n * ```\n *\n * @internal\n */\nexport default class ErrorReadableMock\n  extends Readable\n  implements IReadableMock\n{\n  /**\n   * @param expectedError - error to be passed on callback.\n   * @param options - Readable stream options.\n   */\n  constructor(expectedError: Error, options: ReadableOptions = {}) {\n    super(options);\n    this.expectedError = expectedError;\n  }\n\n  public it: IterableIterator<any> = [][Symbol.iterator]();\n  private expectedError: Error;\n\n  // tslint:disable-next-line:function-name Not responsible of this function name\n  public override _read() {\n    this.destroy(this.expectedError);\n  }\n}\n"
  },
  {
    "path": "test/frameworks/apollo-server.framework.spec.ts",
    "content": "import type { OutgoingHttpHeaders } from 'http';\nimport { ApolloServer, type BaseContext, HeaderMap } from '@apollo/server';\nimport { describe, expect, it, vitest } from 'vitest';\nimport {\n  ServerlessRequest,\n  ServerlessResponse,\n  getEventBodyAsBuffer,\n  waitForStreamComplete,\n} from '../../src';\nimport {\n  type ApolloServerContextArguments,\n  ApolloServerFramework,\n  type DefaultServerlessApolloServerContext,\n} from '../../src/frameworks/apollo-server';\nimport { JsonBodyParserFramework } from '../../src/frameworks/body-parser';\nimport { type TestRouteBuilderMethods } from './utils';\n\nexport const frameworkTestOptions: [\n  method: TestRouteBuilderMethods,\n  path: string,\n  query: string,\n  statusCode: number,\n  expectedValue: string,\n  expectHeaderSet: boolean,\n][] = [\n  ['post', 'GetUser', 'message', 200, 'Joga10', true],\n  ['post', 'ListUser', 'message', 200, 'Unkownn', true],\n  ['post', 'UserCreated', 'message', 200, 'Created', true],\n  ['post', 'WrongQuery', 'nonexist', 400, 'Cannot query field', false],\n];\n\ndescribe(ApolloServerFramework.name, () => {\n  describe('test requests', () => {\n    for (const [\n      method,\n      queryName,\n      query,\n      statusCode,\n      expectedValue,\n      expectHeaderSet,\n    ] of frameworkTestOptions) {\n      it(`${method}${queryName}: should forward request and receive response correctly`, async () => {\n        const app = new ApolloServer<DefaultServerlessApolloServerContext>({\n          typeDefs: 'type Query { message: String }',\n          resolvers: {\n            Query: {\n              message: (_, __, context: ApolloServerContextArguments) => {\n                context.response.setHeader('response-header', 'true');\n\n                return expectedValue;\n              },\n            },\n          },\n        });\n\n        app.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests();\n\n        const stringBody = JSON.stringify({\n          query: `\n            query Query {\n              ${query}\n            }\n        `,\n        });\n        const [bufferBody, bodyLength] = stringBody\n          ? getEventBodyAsBuffer(stringBody, false)\n          : [undefined, 0];\n\n        const framework = new JsonBodyParserFramework(\n          new ApolloServerFramework<DefaultServerlessApolloServerContext>(),\n        );\n\n        const request = new ServerlessRequest({\n          method: method.toUpperCase(),\n          url: '/',\n          headers: {\n            'content-length': String(bodyLength),\n            'request-header': 'true',\n            'content-type': 'application/json',\n          },\n          body: bufferBody,\n        });\n\n        const response = new ServerlessResponse({\n          method: method.toUpperCase(),\n        });\n\n        framework.sendRequest(app, request, response);\n\n        await waitForStreamComplete(response);\n\n        const resultBody = ServerlessResponse.body(response);\n\n        expect(resultBody.toString('utf-8')).toContain(\n          expectedValue !== undefined ? expectedValue : expectedValue,\n        );\n        if (expectHeaderSet) {\n          expect(ServerlessResponse.headers(response)).toHaveProperty(\n            'response-header',\n            'true',\n          );\n        } else {\n          expect(ServerlessResponse.headers(response)).not.toHaveProperty(\n            'response-header',\n            'true',\n          );\n        }\n        expect(response.statusCode).toBe(statusCode);\n      });\n    }\n  });\n\n  describe('async iterator', () => {\n    it('should handle well async iterator', async () => {\n      const app = new ApolloServer<BaseContext>({\n        typeDefs: 'type Query { message: String }',\n        resolvers: {\n          Query: {\n            message: (_, __, context: ApolloServerContextArguments) => {\n              context.response.setHeader('response-header', 'true');\n\n              return 'ok';\n            },\n          },\n        },\n      });\n\n      const asyncContent = ['hello', 'world', '!'];\n\n      // eslint-disable-next-line @typescript-eslint/require-await\n      async function* iterator(values) {\n        for (let i = 0; i < values.length; i++) yield values[i];\n      }\n\n      vitest.spyOn(app, 'executeHTTPGraphQLRequest').mockImplementation(() =>\n        Promise.resolve({\n          status: 200,\n          headers: new HeaderMap(),\n          body: {\n            kind: 'chunked' as const,\n            asyncIterator: iterator(asyncContent),\n          },\n        }),\n      );\n\n      app.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests();\n\n      const stringBody = JSON.stringify({\n        query: `\n            query Query {\n              message\n            }\n        `,\n      });\n\n      const [bufferBody, bodyLength] = stringBody\n        ? getEventBodyAsBuffer(stringBody, false)\n        : [undefined, 0];\n\n      const framework = new JsonBodyParserFramework(\n        new ApolloServerFramework(),\n      );\n\n      const request = new ServerlessRequest({\n        method: 'POST',\n        url: '/',\n        headers: {\n          'content-length': String(bodyLength),\n          'request-header': 'true',\n          'content-type': 'application/json',\n        },\n        body: bufferBody,\n      });\n\n      const response: ServerlessResponse & { flush?: () => void } =\n        new ServerlessResponse({\n          method: 'POST',\n        });\n\n      response.flush = vitest.fn(() => void 0);\n\n      framework.sendRequest(app, request, response);\n\n      await waitForStreamComplete(response);\n\n      const resultBody = ServerlessResponse.body(response);\n\n      expect(resultBody.toString()).toEqual(asyncContent.join(''));\n      expect(response.flush).toHaveBeenNthCalledWith(asyncContent.length);\n    });\n  });\n\n  describe('possible headers', () => {\n    it('should handle all types of OutgoingHttpHeaders', () => {\n      const headers: OutgoingHttpHeaders = {\n        test: 'test',\n        foo: ['bar', 'boe'],\n        bar: undefined,\n        doe: 10,\n      };\n\n      const app = new ApolloServer<BaseContext>({\n        typeDefs: 'type Query { doe: String }',\n        resolvers: {},\n      });\n\n      vitest\n        .spyOn(app, 'executeHTTPGraphQLRequest')\n        .mockImplementation(({ httpGraphQLRequest: { headers } }) => {\n          const objHeaders = Object.fromEntries(headers.entries());\n\n          expect(objHeaders).toHaveProperty('test', 'test');\n          expect(objHeaders).toHaveProperty('foo', 'bar, boe');\n          expect(objHeaders).toHaveProperty('doe', '10');\n          expect(objHeaders).not.toHaveProperty('bar');\n\n          return Promise.resolve({\n            status: 200,\n            body: { kind: 'complete', string: 'ok' },\n            headers: new HeaderMap(),\n          });\n        });\n\n      const request = new ServerlessRequest({\n        method: 'POST',\n        url: '/',\n        headers: headers as any,\n      });\n\n      const response: ServerlessResponse = new ServerlessResponse({\n        method: 'POST',\n      });\n\n      const framework = new ApolloServerFramework();\n\n      framework.sendRequest(app, request, response);\n    });\n  });\n});\n"
  },
  {
    "path": "test/frameworks/body-parser-v2.framework.spec.ts",
    "content": "import { describe, vitest } from 'vitest';\nimport { createBodyParserTests } from './body-parser.framework.helper';\n\nvitest.mock('body-parser', async () => {\n  return await import('body-parser-v2');\n});\n\ndescribe('Body Parser v2', () => {\n  createBodyParserTests();\n});\n"
  },
  {
    "path": "test/frameworks/body-parser.framework.helper.ts",
    "content": "import * as trpc from '@trpc/server';\nimport type { Options } from 'body-parser';\nimport express, { type Express } from 'express';\nimport express_v5 from 'express-v5';\nimport fastify, { type FastifyInstance } from 'fastify';\nimport fastify_v5 from 'fastify-v5';\nimport Application from 'koa';\nimport polka from 'polka';\nimport { type SpyInstance, describe, expect, it, vitest } from 'vitest';\nimport {\n  type FrameworkContract,\n  ServerlessRequest,\n  ServerlessResponse,\n  waitForStreamComplete,\n} from '../../src';\nimport {\n  type BodyParserOptions,\n  JsonBodyParserFramework,\n  RawBodyParserFramework,\n  TextBodyParserFramework,\n  UrlencodedBodyParserFramework,\n} from '../../src/frameworks/body-parser';\nimport { ExpressFramework } from '../../src/frameworks/express';\nimport { FastifyFramework } from '../../src/frameworks/fastify';\nimport { setNoOpForContentType } from '../../src/frameworks/fastify/helpers/no-op-content-parser';\nimport { KoaFramework } from '../../src/frameworks/koa';\nimport { PolkaFramework } from '../../src/frameworks/polka';\nimport {\n  type TrpcAdapterContext,\n  TrpcFramework,\n} from '../../src/frameworks/trpc';\n\ntype BodyParserTest = {\n  name: string;\n  createFramework: <TApp>(\n    framework: FrameworkContract<TApp>,\n  ) => FrameworkContract<TApp>;\n  body: Buffer;\n  contentType: string;\n  expectedBody?: any;\n  notExpectedBody?: any;\n  status: number;\n  expectSendRequestOfTheFrameworkToBeCalled: boolean;\n  skipFrameworks?: (\n    | 'express'\n    | 'fastify'\n    | 'koa'\n    | 'hapi'\n    | 'trpc'\n    | 'polka'\n  )[];\n};\n\nconst bodyParserOptions: BodyParserTest[] = [\n  {\n    name: 'json: default behavior',\n    createFramework: framework => framework,\n    body: Buffer.from(JSON.stringify({ message: 'ok' }), 'utf-8'),\n    contentType: 'application/json',\n    expectedBody: Buffer.from(JSON.stringify({ message: 'ok' }), 'utf-8'),\n    status: 200,\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'json: parse successfuly json',\n    createFramework: framework => new JsonBodyParserFramework(framework),\n    body: Buffer.from(JSON.stringify({ message: 'ok' }), 'utf-8'),\n    contentType: 'application/json',\n    expectedBody: { message: 'ok' },\n    status: 200,\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'json: error on parse, limit',\n    createFramework: framework =>\n      new JsonBodyParserFramework(framework, { limit: 4 }),\n    body: Buffer.from(JSON.stringify({ message: 'ok' }), 'utf-8'),\n    contentType: 'application/json',\n    notExpectedBody: JSON.stringify({ message: 'ok' }),\n    status: 413,\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'json: error on parse, invalid json',\n    createFramework: framework => new JsonBodyParserFramework(framework),\n    body: Buffer.from('{\"potato\":true', 'utf-8'),\n    contentType: 'application/json',\n    notExpectedBody: '{\"potato\":true',\n    status: 400,\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'json: error on parse, invalid json and strict syntax',\n    createFramework: framework =>\n      new JsonBodyParserFramework(framework, { strict: true }),\n    body: Buffer.from('\"potato\":true}', 'utf-8'),\n    contentType: 'application/json',\n    notExpectedBody: '{\"potato\":true',\n    status: 400,\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'text: default behavior',\n    createFramework: framework => framework,\n    body: Buffer.from('potato=cool', 'utf-8'),\n    contentType: 'text/plain',\n    expectedBody: Buffer.from('potato=cool', 'utf-8'),\n    status: 200,\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'text: parse text',\n    createFramework: framework => new TextBodyParserFramework(framework),\n    body: Buffer.from('potato=cool', 'utf-8'),\n    contentType: 'text/plain',\n    expectedBody: 'potato=cool',\n    status: 200,\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n    skipFrameworks: ['trpc'],\n  },\n  {\n    name: 'text: error on size limit',\n    createFramework: framework =>\n      new TextBodyParserFramework(framework, { limit: 4 }),\n    body: Buffer.from('potato=cool', 'utf-8'),\n    contentType: 'text/plain',\n    notExpectedBody: 'potato=cool',\n    status: 413,\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'raw: default behavior',\n    createFramework: framework => framework,\n    body: Buffer.from('potato=cool', 'utf-8'),\n    contentType: 'application/octet-stream',\n    expectedBody: Buffer.from('potato=cool', 'utf-8'),\n    status: 200,\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'raw: parse raw successfuly',\n    createFramework: framework => new RawBodyParserFramework(framework),\n    body: Buffer.from('potato=cool', 'utf-8'),\n    contentType: 'application/octet-stream',\n    expectedBody: Buffer.from('potato=cool', 'utf-8'),\n    status: 200,\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'raw: error on size limit',\n    createFramework: framework =>\n      new RawBodyParserFramework(framework, { limit: 4 }),\n    body: Buffer.from('potato=cool', 'utf-8'),\n    contentType: 'application/octet-stream',\n    notExpectedBody: Buffer.from('potato=cool', 'utf-8'),\n    status: 413,\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'urlencoded: default behavior',\n    createFramework: framework => framework,\n    body: Buffer.from('foo=bar', 'utf-8'),\n    contentType: 'application/x-www-form-urlencoded',\n    expectedBody: Buffer.from('foo=bar', 'utf-8'),\n    status: 200,\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'urlencoded: parse urlencoded',\n    createFramework: framework => new UrlencodedBodyParserFramework(framework),\n    body: Buffer.from('foo=bar', 'utf-8'),\n    contentType: 'application/x-www-form-urlencoded',\n    expectedBody: { foo: 'bar' },\n    status: 200,\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'urlencoded: parse urlencoded extended',\n    createFramework: framework =>\n      new UrlencodedBodyParserFramework(framework, { extended: true }),\n    body: Buffer.from('foo[bar]=test', 'utf-8'),\n    contentType: 'application/x-www-form-urlencoded',\n    expectedBody: { foo: { bar: 'test' } },\n    status: 200,\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'urlencoded: error on max size',\n    createFramework: framework =>\n      new UrlencodedBodyParserFramework(framework, { limit: 3 }),\n    body: Buffer.from('foo=bar', 'utf-8'),\n    contentType: 'application/x-www-form-urlencoded',\n    notExpectedBody: { foo: 'bar' },\n    status: 413,\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n];\n\nfunction createFramework<TApp>(\n  options: BodyParserTest,\n  instance: FrameworkContract<TApp>,\n): [\n  FrameworkContract<TApp>,\n  SpyInstance<Parameters<FrameworkContract<TApp>['sendRequest']>>,\n] {\n  const spy = vitest.spyOn(instance, 'sendRequest');\n\n  return [options.createFramework(instance), spy];\n}\n\nfunction createRequest(body: Buffer, contentType: string): ServerlessRequest {\n  return new ServerlessRequest({\n    method: 'POST',\n    url: '/body',\n    body,\n    headers: {\n      'content-type': contentType,\n      'content-length': Buffer.byteLength(body, 'utf-8').toString(),\n      accept: contentType,\n    },\n  });\n}\n\nfunction createResponse(method: string): ServerlessResponse {\n  return new ServerlessResponse({\n    method,\n  });\n}\n\nasync function handleRestExpects<TApp>(\n  app: TApp,\n  framework: FrameworkContract<TApp>,\n  bodyParserTestOptions: BodyParserTest,\n): Promise<void> {\n  const [bodyParserFramework, spySendRequest] = createFramework(\n    bodyParserTestOptions,\n    framework,\n  );\n\n  const request = createRequest(\n    bodyParserTestOptions.body,\n    bodyParserTestOptions.contentType,\n  );\n  const response = createResponse(request.method!);\n\n  bodyParserFramework.sendRequest(app, request, response);\n\n  await waitForStreamComplete(response);\n\n  const returnedBody = ServerlessResponse.body(response);\n\n  expect(\n    response.statusCode,\n    `Got status ${response.statusCode} instead of ${\n      bodyParserTestOptions.status\n    }. Response Body: ${returnedBody.toString()}`,\n  ).toEqual(bodyParserTestOptions.status);\n\n  if (bodyParserTestOptions.expectSendRequestOfTheFrameworkToBeCalled)\n    expect(spySendRequest).toHaveBeenCalled();\n  else expect(spySendRequest).not.toHaveBeenCalled();\n}\n\nexport function createBodyParserTests() {\n  describe('BodyParserFramework', () => {\n    describe('express', () => {\n      for (const bodyParserTest of bodyParserOptions) {\n        const itFn = bodyParserTest?.skipFrameworks?.includes('express')\n          ? it.skip\n          : it;\n\n        itFn(bodyParserTest.name, async () => {\n          const app = express();\n\n          app.post('/body', (req, res) => {\n            if (bodyParserTest.expectedBody)\n              expect(req.body).toEqual(bodyParserTest.expectedBody);\n            else expect(req.body).not.toEqual(bodyParserTest.notExpectedBody);\n\n            res.send('ok');\n          });\n\n          app.use((err, __, res, _) => {\n            res.emit('error', err);\n          });\n\n          await handleRestExpects(app, new ExpressFramework(), bodyParserTest);\n        });\n      }\n    });\n\n    describe('express-v5', () => {\n      for (const bodyParserTest of bodyParserOptions) {\n        const itFn = bodyParserTest?.skipFrameworks?.includes('express')\n          ? it.skip\n          : it;\n\n        itFn(bodyParserTest.name, async () => {\n          const app = express_v5();\n\n          app.post('/body', (req, res) => {\n            if (bodyParserTest.expectedBody)\n              expect(req.body).toEqual(bodyParserTest.expectedBody);\n            else expect(req.body).not.toEqual(bodyParserTest.notExpectedBody);\n\n            res.send('ok');\n          });\n\n          app.use((err, __, res, _) => {\n            res.emit('error', err);\n          });\n\n          await handleRestExpects(app, new ExpressFramework(), bodyParserTest);\n        });\n      }\n    });\n\n    describe('fastify', () => {\n      for (const bodyParserTest of bodyParserOptions) {\n        const itFn = bodyParserTest?.skipFrameworks?.includes('fastify')\n          ? it.skip\n          : it;\n\n        itFn(bodyParserTest.name, async () => {\n          const app = fastify();\n\n          setNoOpForContentType(app, 'application/json');\n          setNoOpForContentType(app, 'text/plain');\n          setNoOpForContentType(app, 'application/octet-stream');\n          setNoOpForContentType(app, 'application/x-www-form-urlencoded');\n\n          app.post('/body', (req, res) => {\n            if (bodyParserTest.expectedBody)\n              expect(req.body).toEqual(bodyParserTest.expectedBody);\n            else expect(req.body).not.toEqual(bodyParserTest.notExpectedBody);\n\n            res.send('ok');\n          });\n\n          app.setErrorHandler((err, _req, reply) => {\n            reply.raw.emit('error', err);\n          });\n\n          await handleRestExpects(app, new FastifyFramework(), bodyParserTest);\n        });\n      }\n    });\n\n    describe('fastify-v5', () => {\n      for (const bodyParserTest of bodyParserOptions) {\n        const itFn = bodyParserTest?.skipFrameworks?.includes('fastify')\n          ? it.skip\n          : it;\n\n        itFn(bodyParserTest.name, async () => {\n          const app = fastify_v5() as unknown as FastifyInstance;\n\n          setNoOpForContentType(app, 'application/json');\n          setNoOpForContentType(app, 'text/plain');\n          setNoOpForContentType(app, 'application/octet-stream');\n          setNoOpForContentType(app, 'application/x-www-form-urlencoded');\n\n          app.post('/body', (req, res) => {\n            if (bodyParserTest.expectedBody)\n              expect(req.body).toEqual(bodyParserTest.expectedBody);\n            else expect(req.body).not.toEqual(bodyParserTest.notExpectedBody);\n\n            res.send('ok');\n          });\n\n          app.setErrorHandler((err, _req, reply) => {\n            reply.raw.emit('error', err);\n          });\n\n          await handleRestExpects(app, new FastifyFramework(), bodyParserTest);\n        });\n      }\n    });\n\n    describe('koa', () => {\n      for (const bodyParserTest of bodyParserOptions) {\n        const itFn = bodyParserTest?.skipFrameworks?.includes('koa')\n          ? it.skip\n          : it;\n\n        itFn(bodyParserTest.name, async () => {\n          const app = new Application();\n\n          app.onerror = e => {\n            throw e;\n          };\n\n          const next = vitest.fn(ctx => {\n            const body = ctx.req.body;\n\n            if (bodyParserTest.expectedBody)\n              expect(body).toEqual(bodyParserTest.expectedBody);\n            else expect(body).not.toEqual(bodyParserTest.notExpectedBody);\n\n            ctx.status = 200;\n            ctx.body = 'ok';\n          });\n\n          app.use(next);\n\n          await handleRestExpects(app, new KoaFramework(), bodyParserTest);\n        });\n      }\n    });\n\n    describe('hapi', () => {\n      for (const bodyParserTest of bodyParserOptions) {\n        const itFn = bodyParserTest?.skipFrameworks?.includes('hapi')\n          ? it.skip\n          : it;\n\n        itFn(bodyParserTest.name, async () => {\n          const app = new Application();\n\n          app.use(ctx => {\n            const body = (ctx.req as any).body;\n\n            if (bodyParserTest.expectedBody)\n              expect(body).toEqual(bodyParserTest.expectedBody);\n            else expect(body).not.toEqual(bodyParserTest.notExpectedBody);\n\n            ctx.status = 200;\n            ctx.body = 'ok';\n          });\n\n          app.onerror = e => {\n            throw e;\n          };\n\n          await handleRestExpects(app, new KoaFramework(), bodyParserTest);\n        });\n      }\n    });\n\n    describe('trpc', () => {\n      for (const bodyParserTest of bodyParserOptions) {\n        const itFn = bodyParserTest?.skipFrameworks?.includes('trpc')\n          ? it.skip\n          : it;\n\n        itFn(bodyParserTest.name, async () => {\n          const t = trpc.initTRPC\n            .context<TrpcAdapterContext<unknown>>()\n            .create();\n\n          const app = t.router({\n            body: t.procedure\n              .input(inp => inp)\n              .mutation(ctx => {\n                const body = (ctx.ctx.request as any).body;\n\n                if (bodyParserTest.expectedBody)\n                  expect(body).toEqual(bodyParserTest.expectedBody);\n                else expect(body).not.toEqual(bodyParserTest.notExpectedBody);\n\n                return 'ok';\n              }),\n          });\n\n          await handleRestExpects(app, new TrpcFramework(), bodyParserTest);\n        });\n      }\n    });\n\n    describe('polka', () => {\n      for (const bodyParserTest of bodyParserOptions) {\n        const itFn = bodyParserTest?.skipFrameworks?.includes('polka')\n          ? it.skip\n          : it;\n\n        itFn(bodyParserTest.name, async () => {\n          const app = polka();\n\n          app.post('/body', (req, res) => {\n            if (bodyParserTest.expectedBody)\n              expect(req.body).toEqual(bodyParserTest.expectedBody);\n            else expect(req.body).not.toEqual(bodyParserTest.notExpectedBody);\n\n            res.end('ok');\n          });\n\n          await handleRestExpects(app, new PolkaFramework(), bodyParserTest);\n        });\n      }\n    });\n\n    it('should handle correctly on wrong content-encoding', async () => {\n      const app = express();\n\n      const expressFramework = new ExpressFramework();\n      const bodyParserFramework = new TextBodyParserFramework(expressFramework);\n\n      const request = createRequest(\n        Buffer.from('testrandomdata'),\n        'text/plain',\n      );\n      request.headers['content-encoding'] = 'random';\n\n      const response = createResponse('POST');\n\n      bodyParserFramework.sendRequest(app, request, response);\n\n      await waitForStreamComplete(response);\n\n      expect(response.statusCode).toEqual(415);\n    });\n\n    describe('customErrorHandler', () => {\n      it('should be able to set custom error handler', async () => {\n        const app = express();\n\n        const customOptions: Options & BodyParserOptions = {\n          limit: 4,\n          customErrorHandler: (__, response, _) => {\n            response.statusCode = 400;\n            response.end('ok');\n          },\n        };\n\n        const expressFramework = new ExpressFramework();\n        const bodyParserFrameworks: [\n          framework: FrameworkContract<Express>,\n          contentType: string,\n        ][] = [\n          [\n            new TextBodyParserFramework(expressFramework, customOptions),\n            'text/plain',\n          ],\n          [\n            new JsonBodyParserFramework(expressFramework, customOptions),\n            'application/json',\n          ],\n          [\n            new UrlencodedBodyParserFramework(expressFramework, customOptions),\n            'application/x-www-form-urlencoded',\n          ],\n        ];\n\n        for (const [bodyParserFramework, contentType] of bodyParserFrameworks) {\n          const request = createRequest(\n            Buffer.from('testrandomdata'),\n            contentType,\n          );\n          const response = createResponse('POST');\n\n          bodyParserFramework.sendRequest(app, request, response);\n\n          await waitForStreamComplete(response);\n\n          const result = ServerlessResponse.body(response);\n\n          expect(result).toEqual(Buffer.from('ok'));\n          expect(response.statusCode).toEqual(400);\n        }\n      });\n    });\n  });\n}\n"
  },
  {
    "path": "test/frameworks/body-parser.framework.spec.ts",
    "content": "import { describe } from 'vitest';\nimport { createBodyParserTests } from './body-parser.framework.helper';\n\ndescribe('Body Parser v1', () => {\n  createBodyParserTests();\n});\n"
  },
  {
    "path": "test/frameworks/cors.framework.spec.ts",
    "content": "import * as trpc from '@trpc/server';\nimport express from 'express';\nimport fastify from 'fastify';\nimport Application from 'koa';\nimport { type SpyInstance, describe, expect, it, vitest } from 'vitest';\nimport polka from 'polka';\nimport {\n  type BothValueHeaders,\n  type FrameworkContract,\n  ServerlessRequest,\n  ServerlessResponse,\n  waitForStreamComplete,\n} from '../../src';\nimport {\n  CorsFramework,\n  type CorsFrameworkOptions,\n} from '../../src/frameworks/cors';\nimport { ExpressFramework } from '../../src/frameworks/express';\nimport { FastifyFramework } from '../../src/frameworks/fastify';\nimport { KoaFramework } from '../../src/frameworks/koa';\nimport { TrpcFramework } from '../../src/frameworks/trpc';\nimport { PolkaFramework } from '../../src/frameworks/polka';\n\ntype CorsTest = {\n  name: string;\n  method: string;\n  origin: string;\n  options: CorsFrameworkOptions;\n  expectedHeaders: BothValueHeaders;\n  expectSendRequestOfTheFrameworkToBeCalled: boolean;\n};\n\nconst AllowOrigin = 'access-control-allow-origin';\nconst AllowCredentials = 'access-control-allow-credentials';\nconst AllowMethods = 'access-control-allow-methods';\nconst MaxAge = 'access-control-max-age';\nconst AllowHeaders = 'access-control-allow-headers';\n\nconst corsOptions: CorsTest[] = [\n  {\n    name: 'allow all origins',\n    method: 'get',\n    origin: 'http://localhost:3000',\n    options: { origin: '*' },\n    expectedHeaders: { [AllowOrigin]: '*' },\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'allow localhost origin (string)',\n    method: 'get',\n    origin: 'http://localhost:3000',\n    options: { origin: 'http://localhost:3000' },\n    expectedHeaders: { [AllowOrigin]: 'http://localhost:3000', vary: 'Origin' },\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'allow localhost origin (array)',\n    method: 'get',\n    origin: 'http://localhost:3000',\n    options: { origin: ['http://localhost:3000', 'http://google.com'] },\n    expectedHeaders: { [AllowOrigin]: 'http://localhost:3000', vary: 'Origin' },\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'do not send request on options',\n    method: 'options',\n    origin: 'http://localhost:3000',\n    options: { origin: '*' },\n    expectedHeaders: {\n      [AllowOrigin]: '*',\n      [AllowMethods]: 'GET,HEAD,PUT,PATCH,POST,DELETE',\n      vary: 'Access-Control-Request-Headers',\n    },\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'do not send request when origin sent is wrong (string)',\n    method: 'get',\n    origin: 'http://localhost:3000',\n    options: { origin: 'http://example.com:3000' },\n    expectedHeaders: { [AllowOrigin]: 'http://example.com:3000' },\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'do not send request when origin sent is wrong (array)',\n    method: 'get',\n    origin: 'http://localhost:3000',\n    options: { origin: ['http://example.com:3000', 'http://google.com'] },\n    expectedHeaders: {\n      vary: 'Origin',\n    },\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'do not send request when method sent is wrong (string)',\n    method: 'get',\n    origin: 'http://localhost:3000',\n    options: { origin: '*', methods: 'post' },\n    expectedHeaders: { [AllowOrigin]: '*' },\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'do not send request when method sent is wrong (array)',\n    method: 'get',\n    origin: 'http://localhost:3000',\n    options: { origin: '*', methods: ['post'] },\n    expectedHeaders: { [AllowOrigin]: '*' },\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'force process request when origin is wrong',\n    method: 'get',\n    origin: 'http://localhost:3000',\n    options: {\n      origin: 'http://example.com',\n      methods: ['post'],\n      forbiddenOnInvalidOriginOrMethod: false,\n    },\n    expectedHeaders: { [AllowOrigin]: 'http://example.com' },\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'when has credentials',\n    method: 'options',\n    origin: 'http://localhost:3000',\n    options: { credentials: true },\n    expectedHeaders: {\n      [AllowCredentials]: 'true',\n    },\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'when preflight continue is true',\n    method: 'options',\n    origin: 'http://localhost:3000',\n    options: { origin: '*', preflightContinue: true },\n    expectedHeaders: {\n      [AllowOrigin]: '*',\n    },\n    expectSendRequestOfTheFrameworkToBeCalled: true,\n  },\n  {\n    name: 'when allowed headers is sent',\n    method: 'options',\n    origin: 'http://localhost:3000',\n    options: { allowedHeaders: ['x-test'] },\n    expectedHeaders: {\n      [AllowHeaders]: 'x-test',\n    },\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n  {\n    name: 'when max-age is set',\n    method: 'options',\n    origin: 'http://localhost:3000',\n    options: { maxAge: 60 },\n    expectedHeaders: {\n      [MaxAge]: '60',\n    },\n    expectSendRequestOfTheFrameworkToBeCalled: false,\n  },\n];\n\nfunction createFramework<TApp>(\n  options: CorsFrameworkOptions,\n  instance: FrameworkContract<TApp>,\n): [\n  FrameworkContract<TApp>,\n  SpyInstance<Parameters<FrameworkContract<TApp>['sendRequest']>>,\n] {\n  const spy = vitest.spyOn(instance, 'sendRequest');\n\n  return [new CorsFramework(instance, options), spy];\n}\n\nfunction createRequest(method: string, origin: string): ServerlessRequest {\n  return new ServerlessRequest({\n    method,\n    url: '/',\n    headers: {\n      origin: origin,\n    },\n  });\n}\n\nfunction createResponse(method: string): ServerlessResponse {\n  return new ServerlessResponse({\n    method,\n  });\n}\n\nasync function handleRestExpects<TApp>(\n  app: TApp,\n  framework: FrameworkContract<TApp>,\n  corsTest: CorsTest,\n): Promise<void> {\n  const [corsFramework, spySendRequest] = createFramework(\n    corsTest.options,\n    framework,\n  );\n\n  const request = createRequest(corsTest.method, corsTest.origin);\n  const response = createResponse(corsTest.method);\n\n  corsFramework.sendRequest(app, request, response);\n\n  await waitForStreamComplete(response);\n\n  const headers = response.getHeaders();\n\n  for (const expectHeader in corsTest.expectedHeaders) {\n    expect(headers).toHaveProperty(\n      expectHeader,\n      corsTest.expectedHeaders[expectHeader],\n    );\n  }\n\n  if (corsTest.expectSendRequestOfTheFrameworkToBeCalled)\n    expect(spySendRequest).toHaveBeenCalled();\n  else expect(spySendRequest).not.toHaveBeenCalled();\n}\n\ndescribe('CorsFramework', () => {\n  describe('express', () => {\n    for (const corsTest of corsOptions) {\n      it(`${corsTest.method}: ${corsTest.name}`, async () => {\n        const app = express();\n\n        app.get('/', (_, res) => res.json('ok'));\n\n        await handleRestExpects(app, new ExpressFramework(), corsTest);\n      });\n    }\n  });\n\n  describe('fastify', () => {\n    for (const corsTest of corsOptions) {\n      it(`${corsTest.method}: ${corsTest.name}`, async () => {\n        const app = fastify();\n\n        app.get('/', (_, res) => {\n          res.send('ok');\n        });\n\n        await handleRestExpects(app, new FastifyFramework(), corsTest);\n      });\n    }\n  });\n\n  describe('koa', () => {\n    for (const corsTest of corsOptions) {\n      it(`${corsTest.method}: ${corsTest.name}`, async () => {\n        const app = new Application();\n\n        app.use(ctx => {\n          ctx.status = 200;\n          ctx.body = 'ok';\n        });\n\n        await handleRestExpects(app, new KoaFramework(), corsTest);\n      });\n    }\n  });\n\n  describe('hapi', () => {\n    for (const corsTest of corsOptions) {\n      it(`${corsTest.method}: ${corsTest.name}`, async () => {\n        const app = new Application();\n\n        app.use(ctx => {\n          ctx.status = 200;\n          ctx.body = 'ok';\n        });\n\n        await handleRestExpects(app, new KoaFramework(), corsTest);\n      });\n    }\n  });\n\n  describe('trpc', () => {\n    for (const corsTest of corsOptions) {\n      it(`${corsTest.method}: ${corsTest.name}`, async () => {\n        const t = trpc.initTRPC.create();\n\n        const app = t.router({\n          ['/']: t.procedure.query(() => {\n            return 'ok';\n          }),\n        });\n\n        await handleRestExpects(app, new TrpcFramework(), corsTest);\n      });\n    }\n  });\n\n  describe('polka', () => {\n    for (const corsTest of corsOptions) {\n      it(`${corsTest.method}: ${corsTest.name}`, async () => {\n        const app = polka();\n\n        app.get('/', (_, res) => res.end('ok'));\n\n        await handleRestExpects(app, new PolkaFramework(), corsTest);\n      });\n    }\n  });\n});\n"
  },
  {
    "path": "test/frameworks/express-v5.framework.spec.ts",
    "content": "import express from 'express-v5';\nimport { describe } from 'vitest';\nimport { ExpressFramework } from '../../src/frameworks/express';\nimport { type TestRouteBuilderHandler, createTestSuiteFor } from './utils';\n\nfunction createHandler(\n  method: 'get' | 'post' | 'delete' | 'put',\n): TestRouteBuilderHandler<express.Express> {\n  return (app, path, handler) => {\n    app[method](path, (request, response) => {\n      const [statusCode, resultBody, headers] = handler(\n        request.headers,\n        request.body,\n      );\n\n      for (const header of Object.keys(headers))\n        response.header(header, headers[header]);\n\n      response.status(statusCode).json(resultBody);\n    });\n  };\n}\n\ndescribe(ExpressFramework.name, () => {\n  createTestSuiteFor(\n    () => new ExpressFramework(),\n    () => express(),\n    {\n      get: createHandler('get'),\n      delete: createHandler('delete'),\n      post: createHandler('post'),\n      put: createHandler('put'),\n    },\n  );\n});\n"
  },
  {
    "path": "test/frameworks/express.framework.spec.ts",
    "content": "import express, { type Express } from 'express';\nimport { describe } from 'vitest';\nimport { ExpressFramework } from '../../src/frameworks/express';\nimport { type TestRouteBuilderHandler, createTestSuiteFor } from './utils';\n\nfunction createHandler(\n  method: 'get' | 'post' | 'delete' | 'put',\n): TestRouteBuilderHandler<Express> {\n  return (app, path, handler) => {\n    app[method](path, (request, response) => {\n      const [statusCode, resultBody, headers] = handler(\n        request.headers,\n        request.body,\n      );\n\n      for (const header of Object.keys(headers))\n        response.header(header, headers[header]);\n\n      response.status(statusCode).json(resultBody);\n    });\n  };\n}\n\ndescribe(ExpressFramework.name, () => {\n  createTestSuiteFor(\n    () => new ExpressFramework(),\n    () => express(),\n    {\n      get: createHandler('get'),\n      delete: createHandler('delete'),\n      post: createHandler('post'),\n      put: createHandler('put'),\n    },\n  );\n});\n"
  },
  {
    "path": "test/frameworks/fastify-v5.framework.spec.ts",
    "content": "import fastify, { type FastifyInstance } from 'fastify-v5';\nimport { describe } from 'vitest';\nimport { FastifyFramework } from '../../src/frameworks/fastify';\nimport { type TestRouteBuilderHandler, createTestSuiteFor } from './utils';\n\nfunction createHandler(\n  method: 'get' | 'post' | 'delete' | 'put',\n): TestRouteBuilderHandler<FastifyInstance> {\n  return (app, path, handler) => {\n    app[method](path, {}, (request, response) => {\n      const [statusCode, resultBody, headers] = handler(\n        request.headers,\n        request.body,\n      );\n\n      response.headers(headers).code(statusCode).send(resultBody);\n    });\n  };\n}\n\ndescribe(FastifyFramework.name, () => {\n  createTestSuiteFor(\n    () => new FastifyFramework(),\n    () => fastify(),\n    {\n      get: createHandler('get'),\n      delete: createHandler('delete'),\n      post: createHandler('post'),\n      put: createHandler('put'),\n    },\n  );\n});\n"
  },
  {
    "path": "test/frameworks/fastify.framework.spec.ts",
    "content": "import fastify, { type FastifyInstance } from 'fastify';\nimport { describe } from 'vitest';\nimport { FastifyFramework } from '../../src/frameworks/fastify';\nimport { type TestRouteBuilderHandler, createTestSuiteFor } from './utils';\n\nfunction createHandler(\n  method: 'get' | 'post' | 'delete' | 'put',\n): TestRouteBuilderHandler<FastifyInstance> {\n  return (app, path, handler) => {\n    app[method](path, {}, (request, response) => {\n      const [statusCode, resultBody, headers] = handler(\n        request.headers,\n        request.body,\n      );\n\n      response.headers(headers).code(statusCode).send(resultBody);\n    });\n  };\n}\n\ndescribe(FastifyFramework.name, () => {\n  createTestSuiteFor(\n    () => new FastifyFramework(),\n    () => fastify(),\n    {\n      get: createHandler('get'),\n      delete: createHandler('delete'),\n      post: createHandler('post'),\n      put: createHandler('put'),\n    },\n  );\n});\n"
  },
  {
    "path": "test/frameworks/hapi.framework.spec.ts",
    "content": "import { Server } from '@hapi/hapi';\nimport { describe } from 'vitest';\nimport { HapiFramework } from '../../src/frameworks/hapi';\nimport { type TestRouteBuilderHandler, createTestSuiteFor } from './utils';\n\nfunction createHandler(\n  method: 'GET' | 'POST' | 'DELETE' | 'PUT',\n): TestRouteBuilderHandler<Server> {\n  return (app, path, handler) => {\n    app.route({\n      method,\n      path,\n      handler: (request, h) => {\n        const [statusCode, resultBody, headers] = handler(\n          request.headers,\n          request.payload,\n        );\n\n        const response = h.response(resultBody);\n\n        for (const header of Object.keys(headers))\n          response?.header(header, headers[header]);\n\n        response.code(statusCode);\n\n        return response;\n      },\n    });\n  };\n}\n\ndescribe(HapiFramework.name, () => {\n  createTestSuiteFor(\n    () => new HapiFramework(),\n    () => new Server(),\n    {\n      get: createHandler('GET'),\n      delete: createHandler('DELETE'),\n      post: createHandler('POST'),\n      put: createHandler('PUT'),\n    },\n  );\n});\n"
  },
  {
    "path": "test/frameworks/http-deepkit.framework.spec.ts",
    "content": "import { App } from '@deepkit/app';\nimport {\n  HttpKernel,\n  HttpModule,\n  HttpRouterRegistry,\n  JSONResponse,\n} from '@deepkit/http';\nimport { describe, expect, it, vitest } from 'vitest';\nimport {\n  ServerlessRequest,\n  ServerlessResponse,\n  waitForStreamComplete,\n} from '../../src';\nimport { HttpDeepkitFramework } from '../../src/frameworks/deepkit';\n\nit('should convert correctly when the value is not an buffer', async () => {\n  const framework = new HttpDeepkitFramework();\n  const kernel: Partial<HttpKernel> = {\n    handleRequest: vitest.fn((request, response) => {\n      request.pipe(response);\n\n      return void 0 as any;\n    }),\n  };\n  const textCodes = 'test'.split('').map(c => c.charCodeAt(0));\n\n  const request = new ServerlessRequest({\n    body: Uint8Array.of(...textCodes),\n    url: '/test',\n    method: 'POST',\n    headers: {},\n  });\n  const response = new ServerlessResponse({\n    method: 'POST',\n  });\n\n  framework.sendRequest(kernel as HttpKernel, request, response);\n\n  await waitForStreamComplete(response);\n\n  const resultBody = ServerlessResponse.body(response);\n\n  expect(resultBody).toBeInstanceOf(Buffer);\n  expect(resultBody.toString()).toEqual('test');\n});\n\ndescribe('deepkit', () => {\n  it('should return valid json on get request', async () => {\n    const app = new App({\n      imports: [new HttpModule()],\n    });\n\n    const body = { test: 'ok' };\n\n    app.get(HttpRouterRegistry).get('/', () => {\n      return new JSONResponse(body, 200).header('response-header', 'true');\n    });\n\n    const request = new ServerlessRequest({\n      method: 'GET',\n      url: '/',\n      headers: {},\n    });\n\n    const response = new ServerlessResponse({\n      method: 'GET',\n    });\n    const framework = new HttpDeepkitFramework();\n    const httpKernel = app.get(HttpKernel);\n\n    framework.sendRequest(httpKernel, request, response);\n\n    await waitForStreamComplete(response);\n\n    const resultBody = ServerlessResponse.body(response);\n\n    expect(resultBody.toString('utf-8')).toEqual(JSON.stringify(body));\n    expect(response.statusCode).toBe(200);\n    expect(ServerlessResponse.headers(response)).toHaveProperty(\n      'response-header',\n      'true',\n    );\n  });\n});\n"
  },
  {
    "path": "test/frameworks/koa.framework.spec.ts",
    "content": "import Application, { type Context } from 'koa';\nimport { describe } from 'vitest';\nimport { NO_OP } from '../../src';\nimport { KoaFramework } from '../../src/frameworks/koa';\nimport { type TestRouteBuilderHandler, createTestSuiteFor } from './utils';\n\nfunction createHandler(): TestRouteBuilderHandler<Application> {\n  return (app, _, handler) => {\n    app.use((ctx: Context) => {\n      const [statusCode, resultBody, headers] = handler(ctx.headers, NO_OP);\n\n      for (const header of Object.keys(headers))\n        ctx.set(header, headers[header]);\n\n      ctx.status = statusCode;\n      ctx.body = resultBody;\n    });\n  };\n}\n\ndescribe(KoaFramework.name, () => {\n  createTestSuiteFor(\n    () => new KoaFramework(),\n    () => new Application(),\n    {\n      get: createHandler(),\n      delete: createHandler(),\n      post: createHandler(),\n      put: createHandler(),\n    },\n  );\n});\n"
  },
  {
    "path": "test/frameworks/lazy.framework.spec.ts",
    "content": "import { describe, expect, it, vitest } from 'vitest';\nimport {\n  type ILogger,\n  ServerlessRequest,\n  ServerlessResponse,\n  waitForStreamComplete,\n} from '../../src';\nimport { LazyFramework } from '../../src/frameworks/lazy';\nimport { FrameworkMock } from '../mocks/framework.mock';\n\ndescribe(LazyFramework.name, () => {\n  it('should can lazy create an instance of any app and return the cached version', async () => {\n    const appInstance = Symbol('Your app');\n\n    const mockFramework = new FrameworkMock(200, {\n      data: true,\n    });\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    mockFramework.sendRequest = vitest.fn(mockFramework.sendRequest);\n\n    const factory = vitest.fn(\n      () => new Promise(resolve => setTimeout(() => resolve(appInstance), 100)),\n    );\n\n    const framework = new LazyFramework(mockFramework, factory);\n\n    const firstRequest = new ServerlessRequest({\n      method: 'POST',\n      headers: {},\n      url: '/users',\n    });\n    const firstResponse = new ServerlessResponse({\n      method: 'POST',\n    });\n\n    framework.sendRequest(null, firstRequest, firstResponse);\n\n    await waitForStreamComplete(firstResponse);\n\n    expect(framework['factory']).toHaveBeenCalledTimes(1);\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(mockFramework.sendRequest).toHaveBeenLastCalledWith(\n      appInstance,\n      firstRequest,\n      firstResponse,\n    );\n\n    const secondRequest = new ServerlessRequest({\n      method: 'GET',\n      headers: {},\n      url: '/users',\n    });\n    const secondResponse = new ServerlessResponse({\n      method: 'GET',\n    });\n\n    framework.sendRequest(null, secondRequest, secondResponse);\n\n    await waitForStreamComplete(secondResponse);\n\n    expect(factory).toHaveBeenCalledTimes(1);\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(mockFramework.sendRequest).toHaveBeenCalledTimes(2);\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(mockFramework.sendRequest).toHaveBeenLastCalledWith(\n      appInstance,\n      secondRequest,\n      secondResponse,\n    );\n  });\n\n  it('should throw error if error occours in factory function', async () => {\n    const mockFramework = new FrameworkMock(200, {\n      data: true,\n    });\n\n    const mockLogger = { error: vitest.fn() } as unknown as ILogger;\n    const error = new Error('Something Wrong Occours');\n\n    const framework = new LazyFramework(\n      mockFramework,\n      () => Promise.reject(error),\n      mockLogger,\n    );\n\n    const request = new ServerlessRequest({\n      method: 'GET',\n      headers: {},\n      url: '/users',\n    });\n    const response = new ServerlessResponse({\n      method: 'GET',\n    });\n\n    framework.sendRequest(null, request, response);\n\n    await expect(\n      async () => await waitForStreamComplete(response),\n    ).rejects.toThrowError('factory is not valid,');\n  });\n});\n"
  },
  {
    "path": "test/frameworks/polka.framework.spec.ts",
    "content": "import { describe } from 'vitest';\nimport polka, { type Polka } from 'polka';\nimport { PolkaFramework } from '../../src/frameworks/polka';\nimport { type TestRouteBuilderHandler, createTestSuiteFor } from './utils';\n\nfunction createHandler(\n  method: 'get' | 'post' | 'delete' | 'put',\n): TestRouteBuilderHandler<Polka> {\n  return (app, path, handler) => {\n    app[method](path, (request, response) => {\n      const [statusCode, resultBody, headers] = handler(\n        request.headers,\n        request.body,\n      );\n\n      for (const header of Object.keys(headers))\n        response.setHeader(header, headers[header]);\n\n      response.statusCode = statusCode;\n      response.end(JSON.stringify(resultBody));\n    });\n  };\n}\n\ndescribe(PolkaFramework.name, () => {\n  createTestSuiteFor(\n    () => new PolkaFramework(),\n    () => polka(),\n    {\n      get: createHandler('get'),\n      delete: createHandler('delete'),\n      post: createHandler('post'),\n      put: createHandler('put'),\n    },\n  );\n});\n"
  },
  {
    "path": "test/frameworks/trpc.framework.spec.ts",
    "content": "import * as trpc from '@trpc/server';\nimport { type AnyRouter } from '@trpc/server';\nimport { describe, expect, it } from 'vitest';\nimport {\n  NO_OP,\n  ServerlessRequest,\n  ServerlessResponse,\n  getEventBodyAsBuffer,\n  waitForStreamComplete,\n} from '../../src';\nimport {\n  BufferToJSObjectTransformer,\n  type TrpcAdapterContext,\n  TrpcFramework,\n} from '../../src/frameworks/trpc';\nimport { type TestRouteBuilderHandler, frameworkTestOptions } from './utils';\n\ntype TrpcContext = TrpcAdapterContext<unknown>;\n\nfunction createHandler(\n  method: 'get' | 'post' | 'delete' | 'put',\n): TestRouteBuilderHandler<ReturnType<typeof createRouter>, AnyRouter> {\n  return (app, path, handler) => {\n    if (method === 'get') {\n      return app.router({\n        [path]: app.procedure.query(({ ctx, input }) => {\n          const [statusCode, resultBody, headers] = handler(\n            ctx.getHeaders(),\n            input,\n          );\n\n          for (const header of Object.keys(headers))\n            ctx.setHeader(header, headers[header]);\n\n          ctx.setStatus(statusCode);\n\n          return resultBody;\n        }),\n      });\n    } else {\n      return app.router({\n        [path]: app.procedure\n          .input(inp => inp)\n          .mutation(({ ctx, input }) => {\n            const [statusCode, resultBody, headers] = handler(\n              ctx.getHeaders(),\n              input,\n            );\n\n            for (const header of Object.keys(headers))\n              ctx.setHeader(header, headers[header]);\n\n            ctx.setStatus(statusCode);\n\n            return resultBody;\n          }),\n      });\n    }\n  };\n}\n\nfunction createRouter() {\n  return trpc.initTRPC.context<TrpcContext>().create();\n}\n\nconst validTestOptions = frameworkTestOptions.filter(\n  ([method]) => method === 'post' || method === 'get',\n);\n\ndescribe('TrpcFramework', () => {\n  for (const [\n    method,\n    path,\n    statusCode,\n    body,\n    expectedValue,\n  ] of validTestOptions) {\n    const formattedPath = path.replace('/', '').replace(/\\//g, '.');\n    const requestUrl = '/' + formattedPath;\n\n    it(`${method}:${formattedPath}: should forward request and receive response correctly`, async () => {\n      const app = createRouter();\n      const handler = createHandler(method);\n\n      const resolvedApp = handler(\n        app,\n        formattedPath,\n        (requestHeaders, requestBody) => {\n          expect(requestHeaders).toHaveProperty('request-header', 'true');\n\n          if (\n            (method === 'post' || method === 'put') &&\n            requestBody !== NO_OP\n          ) {\n            const parsedRequestBody =\n              requestBody instanceof Buffer\n                ? JSON.parse(requestBody.toString('utf-8'))\n                : requestBody;\n\n            expect(parsedRequestBody).toEqual(body);\n          }\n\n          return [statusCode, body, { 'response-header': 'true' }];\n        },\n      );\n\n      const framework = new TrpcFramework<TrpcAdapterContext<unknown>>();\n\n      const stringBody = body ? JSON.stringify(body) : body;\n      const [bufferBody, bodyLength] = stringBody\n        ? getEventBodyAsBuffer(stringBody, false)\n        : [undefined, 0];\n\n      const request = new ServerlessRequest({\n        method: method.toUpperCase(),\n        url:\n          method !== 'get'\n            ? requestUrl\n            : requestUrl + `?input=${encodeURIComponent(JSON.stringify(body))}`,\n        headers: {\n          'content-length': String(bodyLength),\n          'request-header': 'true',\n          ...(body && {\n            'content-type': 'application/json',\n          }),\n        },\n        body: bufferBody,\n        remoteAddress: '1.1.1.1',\n      });\n\n      const response = new ServerlessResponse({\n        method: method.toUpperCase(),\n      });\n\n      framework.sendRequest(resolvedApp, request, response);\n\n      await waitForStreamComplete(response);\n\n      const resultBody = ServerlessResponse.body(response);\n\n      expect(\n        expectedValue !== undefined\n          ? expectedValue\n          : JSON.stringify({ result: { data: body } }),\n      ).toEqual(resultBody.toString('utf-8'));\n      expect(response.statusCode).toBe(statusCode);\n      expect(ServerlessResponse.headers(response)).toHaveProperty(\n        'response-header',\n        'true',\n      );\n    });\n  }\n\n  it('should enable create custom contexts', async () => {\n    type Context = { currentDate: Date };\n    type CustomContext = TrpcAdapterContext<Context>;\n\n    const currentDate = new Date();\n    const t = trpc.initTRPC.context<CustomContext>().create();\n    const app = t.router({\n      test: t.procedure.query(function ({ ctx }) {\n        expect(ctx).toHaveProperty('currentDate');\n\n        ctx.setStatus(201);\n      }),\n    });\n\n    const request = new ServerlessRequest({\n      method: 'GET',\n      url: '/test',\n      headers: {\n        test: 'header',\n      },\n      body: undefined,\n      remoteAddress: '1.1.1.1',\n    });\n\n    const firstResponse = new ServerlessResponse({\n      method: 'get',\n    });\n\n    const secondResponse = new ServerlessResponse({\n      method: 'get',\n    });\n\n    const firstFramework = new TrpcFramework<TrpcAdapterContext<Context>>({\n      createContext: async () => Promise.resolve({ currentDate }),\n    });\n\n    const secondFramework = new TrpcFramework<TrpcAdapterContext<Context>>({\n      createContext: () => ({ currentDate }),\n    });\n\n    firstFramework.sendRequest(app, request, firstResponse);\n    secondFramework.sendRequest(app, request, secondResponse);\n\n    await waitForStreamComplete(firstResponse);\n    await waitForStreamComplete(secondResponse);\n\n    const firstResultBody = ServerlessResponse.body(firstResponse);\n    const secondResultBody = ServerlessResponse.body(secondResponse);\n\n    const emptyResponse = JSON.stringify({\n      result: {},\n    });\n\n    expect(firstResultBody.toString('utf-8')).toEqual(emptyResponse);\n    expect(secondResultBody.toString('utf-8')).toEqual(emptyResponse);\n  });\n\n  it('should correctly send default methods inside context', async () => {\n    const t = createRouter();\n    const app = t.router({\n      test: t.procedure.query(({ ctx }) => {\n        expect(ctx.request).toBeDefined();\n        expect(ctx.response).toBeDefined();\n\n        expect(ctx.getMethod()).toEqual('GET');\n        expect(ctx.getUrl()).toEqual('/test');\n        expect(ctx.getIp()).toEqual('1.1.1.1');\n        expect(ctx.getHeaders()).toHaveProperty('test', 'header');\n        expect(ctx.getHeader('test')).toEqual('header');\n        expect(ctx.getMethod()).toEqual('GET');\n\n        ctx.setStatus(204);\n        ctx.setHeader('test2', 'batata');\n        ctx.removeHeader('test2');\n      }),\n    });\n\n    const framework = new TrpcFramework<TrpcAdapterContext<unknown>>();\n\n    const request = new ServerlessRequest({\n      method: 'GET',\n      url: '/test',\n      headers: {\n        test: 'header',\n      },\n      body: undefined,\n      remoteAddress: '1.1.1.1',\n    });\n\n    const response = new ServerlessResponse({\n      method: 'get',\n    });\n\n    framework.sendRequest(app, request, response);\n\n    await waitForStreamComplete(response);\n\n    expect(response.statusCode).toEqual(204);\n    expect(response.headers).not.toHaveProperty('test2');\n  });\n});\n\ndescribe(BufferToJSObjectTransformer.name, () => {\n  it('should correctly parse json when came from buffer', () => {\n    const jsonObject = { batata: true };\n    const testJson = JSON.stringify(jsonObject);\n    const transformer = new BufferToJSObjectTransformer();\n\n    const buffer = Buffer.from(testJson, 'utf-8');\n\n    expect(transformer.deserialize(buffer)).toEqual(jsonObject);\n  });\n\n  it('should dont deserialize the value when is not an buffer', () => {\n    const values = [Symbol('do nothing'), 'test', 434];\n    const transformer = new BufferToJSObjectTransformer();\n\n    for (const value of values)\n      expect(transformer.deserialize(value)).toEqual(value);\n  });\n\n  it('should dont modify the value when serialize', () => {\n    const symbol = Symbol('do nothing');\n    const transformer = new BufferToJSObjectTransformer();\n\n    expect(transformer.serialize(symbol)).toEqual(symbol);\n  });\n\n  it('should throw error when buffer is not an JSON', () => {\n    const xml = '<potato>true</potato>';\n    const transformer = new BufferToJSObjectTransformer();\n\n    const buffer = Buffer.from(xml, 'utf-8');\n\n    expect(() => transformer.deserialize(buffer)).toThrow();\n  });\n});\n"
  },
  {
    "path": "test/frameworks/utils.ts",
    "content": "import { expect, it } from 'vitest';\nimport {\n  type FrameworkContract,\n  NO_OP,\n  ServerlessRequest,\n  ServerlessResponse,\n  getEventBodyAsBuffer,\n  waitForStreamComplete,\n} from '../../src';\n\nexport type TestRouteBuilderHandler<TApp, TOutput = void> = (\n  app: TApp,\n  path: string,\n  handler: (\n    headers: any,\n    body: any,\n  ) => [statusCode: number, body: any, headers: any],\n) => TOutput;\n\nexport type TestRouteBuilderMethods = 'get' | 'post' | 'delete' | 'put';\n\nexport type TestRouteBuilder<TApp> = Record<\n  TestRouteBuilderMethods,\n  TestRouteBuilderHandler<TApp>\n>;\n\nexport type TestOptions = [\n  method: TestRouteBuilderMethods,\n  path: string,\n  statusCode: number,\n  body: any,\n  expectedValue?: string,\n];\n\nexport const frameworkTestOptions: TestOptions[] = [\n  ['get', '/', 200, [{ name: 'Joga10' }]],\n  ['get', '/', 200, [{ name: 'Joga10' }]],\n  ['get', '/users', 200, [{ name: 'Joga10' }]],\n  ['get', '/users/list', 200, []],\n  ['get', '/users/1', 404, { didntFind: 'entity' }],\n  ['get', '/users/2', 404, { notFound: true }],\n  ['post', '/users/error', 401, { unathorized: true }],\n  ['post', '/users', 201, { success: true }],\n  ['put', '/users/1', 201, { updated: true }],\n  ['put', '/users/2', 404, { notFound: true }],\n  ['put', '/users/3', 404, { didntFind: 'entity' }],\n  ['delete', '/users/1', 200, { deleted: true }],\n  ['delete', '/users/2', 401, { unathorized: true }],\n  ['get', '/bad-gateway', 503, { error: true }],\n];\n\nexport function createTestSuiteFor<TApp, TFrameworkApp = TApp>(\n  frameworkFactory: () => FrameworkContract<TFrameworkApp>,\n  appFactory: () => TApp | Promise<TApp>,\n  routeBuilder: TestRouteBuilder<TApp>,\n  appToFrameworkApp?: (TApp) => TFrameworkApp,\n  tearDown?: (app: TApp) => Promise<void>,\n  skip?: boolean,\n  testOptions: TestOptions[] = frameworkTestOptions,\n): void {\n  for (const [method, path, statusCode, body, expectedValue] of testOptions) {\n    const itFn = skip ? it.skip : it;\n\n    itFn(\n      `${method}${path}: should forward request and receive response correctly`,\n      async () => {\n        const app = await appFactory();\n\n        routeBuilder[method](\n          app,\n          path || '/',\n          (requestHeaders, requestBody) => {\n            expect(requestHeaders).toHaveProperty('request-header', 'true');\n\n            if (\n              (method === 'post' || method === 'put') &&\n              requestBody !== NO_OP\n            ) {\n              const parsedRequestBody =\n                requestBody instanceof Buffer\n                  ? JSON.parse(requestBody.toString('utf-8'))\n                  : requestBody;\n\n              expect(parsedRequestBody || null).toEqual(body || null);\n            }\n\n            return [statusCode, body, { 'response-header': 'true' }];\n          },\n        );\n\n        const stringBody = body ? JSON.stringify(body) : body;\n        const [bufferBody, bodyLength] = stringBody\n          ? getEventBodyAsBuffer(stringBody, false)\n          : [undefined, 0];\n\n        const framework = frameworkFactory();\n        const request = new ServerlessRequest({\n          method: method.toUpperCase(),\n          url: path,\n          headers: {\n            'content-length': String(bodyLength),\n            'request-header': 'true',\n            ...(body && {\n              'content-type': 'application/json',\n            }),\n          },\n          body: bufferBody,\n        });\n\n        const response = new ServerlessResponse({\n          method: method.toUpperCase(),\n        });\n\n        const frameworkApp = appToFrameworkApp\n          ? appToFrameworkApp(app)\n          : (app as unknown as TFrameworkApp);\n\n        framework.sendRequest(frameworkApp, request, response);\n\n        await waitForStreamComplete(response);\n\n        if (tearDown) await tearDown(app);\n\n        const resultBody = ServerlessResponse.body(response);\n\n        expect(resultBody.toString('utf-8')).toEqual(\n          expectedValue !== undefined ? expectedValue : JSON.stringify(body),\n        );\n        expect(response.statusCode).toBe(statusCode);\n        expect(ServerlessResponse.headers(response)).toHaveProperty(\n          'response-header',\n          'true',\n        );\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "test/handlers/aws-stream.handler.spec.ts",
    "content": "import { createReadStream, readFileSync } from 'fs';\nimport { join } from 'path';\nimport express from 'express';\nimport { WritableMock } from 'stream-mock/lib/writable';\nimport { afterEach, beforeEach, describe, expect, it, vitest } from 'vitest';\nimport { type ILogger, getCurrentInvoke } from '../../src';\nimport { ApiGatewayV2Adapter } from '../../src/adapters/aws';\nimport { ExpressFramework } from '../../src/frameworks/express';\nimport { AwsStreamHandler } from '../../src/handlers/aws';\nimport { DummyResolver } from '../../src/resolvers/dummy';\nimport { createApiGatewayV2 } from '../adapters/aws/utils/api-gateway-v2';\n\ndescribe('AwsStreamHandler', () => {\n  const awsStreamHandler = new AwsStreamHandler();\n\n  const apiGatewayAdapter = new ApiGatewayV2Adapter();\n  const adapters = [apiGatewayAdapter];\n  const resolver = new DummyResolver();\n  const binarySettings = { contentEncodings: [], contentTypes: [] };\n  const respondWithErrors = true;\n  const logger: ILogger = {\n    debug: vitest.fn((m, callbackOrString) => {\n      expect(typeof m === 'string').toBeTruthy();\n      const content =\n        typeof callbackOrString === 'function'\n          ? callbackOrString()\n          : callbackOrString || 'no-second-arg';\n      expect(content).toBeTruthy();\n    }),\n    error: vitest.fn(),\n    verbose: vitest.fn(),\n    info: vitest.fn(),\n    warn: vitest.fn(),\n  };\n\n  beforeEach(() => {\n    (global as any).awslambda = {\n      streamifyResponse: vitest.fn(fn => fn),\n      HttpResponseStream: { from: vitest.fn(r => r) },\n    };\n  });\n\n  afterEach(() => {\n    (global as any).awslambda = undefined;\n  });\n\n  it('should return the correct bytes of chunked stream', async () => {\n    const app = express();\n    const file = readFileSync(join(__dirname, 'bitcoin.pdf'));\n\n    app.get('/', (_, res) => {\n      const readable = createReadStream(join(__dirname, 'bitcoin.pdf'));\n\n      res.statusCode = 200;\n      res.setHeader('content-type', 'application/pdf');\n      readable.pipe(res);\n    });\n\n    const expressFramework = new ExpressFramework();\n\n    const handler = awsStreamHandler.getHandler(\n      app,\n      expressFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    const event = createApiGatewayV2('GET', '/', {}, { test: 'true' });\n    const context = { test: Symbol('unique') };\n\n    const writable = new WritableMock();\n\n    await handler(event, writable, context);\n\n    expect(getCurrentInvoke()).toHaveProperty('event', event);\n    expect(getCurrentInvoke()).toHaveProperty('context', context);\n\n    const finalBuffer = Buffer.concat(writable.data);\n\n    expect(Buffer.byteLength(finalBuffer)).toBe(Buffer.byteLength(file));\n  });\n\n  it('should return the correct bytes of chunked stream with eagerly flushed headers', async () => {\n    const app = express();\n    const file = readFileSync(join(__dirname, 'bitcoin.pdf'));\n\n    app.get('/', (_, res) => {\n      const readable = createReadStream(join(__dirname, 'bitcoin.pdf'));\n\n      res.statusCode = 200;\n      res.setHeader('content-type', 'application/pdf');\n      res.flushHeaders();\n      readable.pipe(res);\n    });\n\n    const expressFramework = new ExpressFramework();\n\n    const handler = awsStreamHandler.getHandler(\n      app,\n      expressFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    const event = createApiGatewayV2('GET', '/', {}, { test: 'true' });\n    const context = { test: Symbol('unique') };\n\n    const writable = new WritableMock();\n\n    await handler(event, writable, context);\n\n    expect(getCurrentInvoke()).toHaveProperty('event', event);\n    expect(getCurrentInvoke()).toHaveProperty('context', context);\n\n    const finalBuffer = Buffer.concat(writable.data);\n\n    expect(Buffer.byteLength(finalBuffer)).toBe(Buffer.byteLength(file));\n  });\n\n  it('should return the correct bytes of json', async () => {\n    const app = express();\n\n    app.get('/', (_, res) => {\n      return res.json({ test: 'true' });\n    });\n\n    const expressFramework = new ExpressFramework();\n\n    const handler = awsStreamHandler.getHandler(\n      app,\n      expressFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    const event = createApiGatewayV2('GET', '/', {}, { test: 'true' });\n    const context = { test: Symbol('unique') };\n\n    const writable = new WritableMock();\n\n    await handler(event, writable, context);\n\n    expect(getCurrentInvoke()).toHaveProperty('event', event);\n    expect(getCurrentInvoke()).toHaveProperty('context', context);\n\n    const finalBuffer = Buffer.concat(writable.data);\n\n    expect(finalBuffer.toString()).toBe(JSON.stringify({ test: 'true' }));\n  });\n\n  it('should handle redirect with status 304', async () => {\n    const app = express();\n\n    app.get('/', (_, res) => {\n      return res.redirect(304, '/test');\n    });\n\n    const expressFramework = new ExpressFramework();\n\n    const handler = awsStreamHandler.getHandler(\n      app,\n      expressFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    const event = createApiGatewayV2('GET', '/', undefined);\n    const context = { test: Symbol('unique') };\n\n    const writable = new WritableMock();\n    const write = vitest.spyOn(writable, 'write');\n\n    await handler(event, writable, context);\n\n    expect(getCurrentInvoke()).toHaveProperty('event', event);\n    expect(getCurrentInvoke()).toHaveProperty('context', context);\n\n    expect(write).toHaveBeenCalledWith('');\n\n    const finalBuffer = Buffer.concat(writable.data);\n\n    expect(finalBuffer.toString()).toBe('');\n  });\n\n  for (const statusCode of [300, 301, 302, 303, 305, 306, 307, 308]) {\n    it(`should handle redirect with status ${statusCode}`, async () => {\n      const app = express();\n\n      app.get('/', (_, res) => {\n        return res.redirect(statusCode, '/test');\n      });\n\n      const expressFramework = new ExpressFramework();\n\n      const handler = awsStreamHandler.getHandler(\n        app,\n        expressFramework,\n        adapters,\n        resolver,\n        binarySettings,\n        respondWithErrors,\n        logger,\n      );\n\n      const event = createApiGatewayV2('GET', '/', undefined);\n      const context = { test: Symbol('unique') };\n\n      const writable = new WritableMock();\n      const write = vitest.spyOn(writable, 'write');\n\n      await handler(event, writable, context);\n\n      expect(getCurrentInvoke()).toHaveProperty('event', event);\n      expect(getCurrentInvoke()).toHaveProperty('context', context);\n\n      expect(write).toHaveBeenCalled();\n\n      const finalBuffer = Buffer.concat(writable.data);\n\n      expect(finalBuffer.toString()).toContain('Redirecting to /test');\n    });\n  }\n\n  for (const statusCode of [200, 201, 202, 203, 204, 400, 401, 403, 404]) {\n    it(`should handle no content with status ${statusCode}`, async () => {\n      const app = express();\n\n      app.get('/', (_, res) => {\n        return res.status(statusCode).end();\n      });\n\n      const expressFramework = new ExpressFramework();\n\n      const handler = awsStreamHandler.getHandler(\n        app,\n        expressFramework,\n        adapters,\n        resolver,\n        binarySettings,\n        respondWithErrors,\n        logger,\n      );\n\n      const event = createApiGatewayV2('GET', '/', undefined);\n      const context = { test: Symbol('unique') };\n\n      const writable = new WritableMock();\n      const write = vitest.spyOn(writable, 'write');\n\n      await handler(event, writable, context);\n\n      expect(getCurrentInvoke()).toHaveProperty('event', event);\n      expect(getCurrentInvoke()).toHaveProperty('context', context);\n\n      expect(write).toHaveBeenCalledWith('');\n\n      const finalBuffer = Buffer.concat(writable.data);\n\n      expect(finalBuffer.toString()).toBe('');\n    });\n  }\n\n  for (const statusCode of [200, 201, 202, 203, 204, 400, 401, 403, 404]) {\n    it(`should handle writeHead with no content and status ${statusCode}`, async () => {\n      const app = express();\n\n      app.get('/', (_, res) => {\n        return res.writeHead(statusCode).end();\n      });\n\n      const expressFramework = new ExpressFramework();\n\n      const handler = awsStreamHandler.getHandler(\n        app,\n        expressFramework,\n        adapters,\n        resolver,\n        binarySettings,\n        respondWithErrors,\n        logger,\n      );\n\n      const event = createApiGatewayV2('GET', '/', undefined);\n      const context = { test: Symbol('unique') };\n\n      const writable = new WritableMock();\n      const write = vitest.spyOn(writable, 'write');\n\n      await handler(event, writable, context);\n\n      expect(getCurrentInvoke()).toHaveProperty('event', event);\n      expect(getCurrentInvoke()).toHaveProperty('context', context);\n\n      expect(write).toHaveBeenCalledWith('');\n\n      const finalBuffer = Buffer.concat(writable.data);\n\n      expect(finalBuffer.toString()).toBe('');\n    });\n  }\n\n  it('should handle HEAD requests', async () => {\n    const app = express();\n\n    app.head('/', (_, res) => {\n      return res.set(200).end();\n    });\n\n    const expressFramework = new ExpressFramework();\n\n    const handler = awsStreamHandler.getHandler(\n      app,\n      expressFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    const event = createApiGatewayV2('HEAD', '/', undefined);\n    const context = { test: Symbol('unique') };\n\n    const writable = new WritableMock();\n    const write = vitest.spyOn(writable, 'write');\n\n    await handler(event, writable, context);\n\n    expect(getCurrentInvoke()).toHaveProperty('event', event);\n    expect(getCurrentInvoke()).toHaveProperty('context', context);\n\n    expect(write).toHaveBeenCalledWith('');\n\n    const finalBuffer = Buffer.concat(writable.data);\n\n    expect(finalBuffer.toString()).toBe('');\n  });\n\n  it('should handle correctly the cookies', async () => {\n    const app = express();\n\n    app.get('/', (_, res) => {\n      res.setHeader('set-cookie', 'test=1');\n      res.json({ ok: true });\n    });\n\n    const expressFramework = new ExpressFramework();\n\n    const handler = awsStreamHandler.getHandler(\n      app,\n      expressFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    const event = createApiGatewayV2('GET', '/', {}, { test: 'true' });\n    const context = { test: Symbol('unique') };\n\n    const writable = new WritableMock();\n\n    await handler(event, writable, context);\n\n    expect(getCurrentInvoke()).toHaveProperty('event', event);\n    expect(getCurrentInvoke()).toHaveProperty('context', context);\n\n    expect(\n      (global as any).awslambda.HttpResponseStream.from,\n    ).toHaveBeenCalledWith(\n      expect.anything(),\n      expect.objectContaining({\n        headers: expect.not.objectContaining({\n          'set-cookie': 'test=1',\n        }),\n        cookies: ['test=1'],\n      }),\n    );\n  });\n\n  it('should handle correctly the cookies array', async () => {\n    const app = express();\n\n    app.get('/', (_, res) => {\n      res.setHeader('set-cookie', ['test=1', 'test2=3']);\n      res.json({ ok: true });\n    });\n\n    const expressFramework = new ExpressFramework();\n\n    const handler = awsStreamHandler.getHandler(\n      app,\n      expressFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    const event = createApiGatewayV2('GET', '/', {}, { test: 'true' });\n    const context = { test: Symbol('unique') };\n\n    const writable = new WritableMock();\n\n    await handler(event, writable, context);\n\n    expect(getCurrentInvoke()).toHaveProperty('event', event);\n    expect(getCurrentInvoke()).toHaveProperty('context', context);\n\n    expect(\n      (global as any).awslambda.HttpResponseStream.from,\n    ).toHaveBeenCalledWith(\n      expect.anything(),\n      expect.objectContaining({\n        headers: expect.not.objectContaining({\n          'set-cookie': 'test=1',\n        }),\n        cookies: ['test=1', 'test2=3'],\n      }),\n    );\n  });\n\n  it('callbackWaitsForEmptyEventLoop should not be modified', async () => {\n    const app = express();\n\n    app.get('/', (_, res) => {\n      res.json({ ok: true });\n    });\n\n    const expressFramework = new ExpressFramework();\n\n    const handler = awsStreamHandler.getHandler(\n      app,\n      expressFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    const event = createApiGatewayV2('GET', '/', {}, { test: 'true' });\n    const defaultValueForCallback = Symbol('1');\n    const context = {\n      test: Symbol('unique'),\n      callbackWaitsForEmptyEventLoop: defaultValueForCallback,\n    };\n\n    const writable = new WritableMock();\n\n    await handler(event, writable, context);\n\n    expect(context).toHaveProperty(\n      'callbackWaitsForEmptyEventLoop',\n      defaultValueForCallback,\n    );\n  });\n\n  describe('callbackWaitsForEmptyEventLoop should be changed', () => {\n    for (const value of [true, false]) {\n      it(`to ${value}`, async () => {\n        const app = express();\n\n        app.get('/', (_, res) => {\n          res.json({ ok: true });\n        });\n\n        const expressFramework = new ExpressFramework();\n        const customAwsHandler = new AwsStreamHandler({\n          callbackWaitsForEmptyEventLoop: value,\n        });\n\n        const handler = customAwsHandler.getHandler(\n          app,\n          expressFramework,\n          adapters,\n          resolver,\n          binarySettings,\n          respondWithErrors,\n          logger,\n        );\n\n        const event = createApiGatewayV2('GET', '/', {}, { test: 'true' });\n        const defaultValueForCallback = Symbol('test');\n        const context = {\n          test: Symbol('unique'),\n          callbackWaitsForEmptyEventLoop: defaultValueForCallback,\n        };\n\n        const writable = new WritableMock();\n\n        await handler(event, writable, context);\n\n        expect(context).toHaveProperty('callbackWaitsForEmptyEventLoop', value);\n      });\n    }\n  });\n});\n"
  },
  {
    "path": "test/handlers/azure.handler.spec.ts",
    "content": "import { describe, expect, it, vitest } from 'vitest';\nimport type { HttpRequest } from '@azure/functions';\nimport { type ILogger, createDefaultLogger } from '../../src';\nimport { HttpTriggerV4Adapter } from '../../src/adapters/azure';\nimport { AzureHandler } from '../../src/handlers/azure';\nimport { DefaultHandler } from '../../src/handlers/default';\nimport { PromiseResolver } from '../../src/resolvers/promise';\nimport {\n  createHttpTriggerContext,\n  createHttpTriggerEvent,\n} from '../adapters/azure/utils/http-trigger';\nimport { FrameworkMock } from '../mocks/framework.mock';\n\ndescribe(AzureHandler.name, () => {\n  const azureHandlerFactory = new AzureHandler<\n    null,\n    HttpRequest,\n    any,\n    any,\n    any\n  >();\n\n  const app = null;\n  const response = { batata: true };\n  const mockFramework = new FrameworkMock(200, response);\n  const httpTriggerAdapter = new HttpTriggerV4Adapter();\n  const adapters = [httpTriggerAdapter];\n  const resolver = new PromiseResolver();\n  const binarySettings = { contentEncodings: [], contentTypes: [] };\n  const respondWithErrors = true;\n  const logger: ILogger = {\n    debug: vitest.fn(),\n    error: vitest.fn(),\n    verbose: vitest.fn(),\n    info: vitest.fn(),\n    warn: vitest.fn(),\n  };\n\n  it('should call default handler with correct params', () => {\n    const defaultServerlessHandler = vitest.fn(() => Promise.resolve(response));\n    const defaultGetHandler = vitest\n      .spyOn(DefaultHandler.prototype, 'getHandler')\n      .mockImplementation(() => defaultServerlessHandler);\n\n    const getHandlerArguments = [\n      app,\n      mockFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    ] as const;\n\n    const azureHandler = azureHandlerFactory.getHandler(...getHandlerArguments);\n\n    const event = createHttpTriggerEvent('GET', '/');\n    const context = createHttpTriggerContext('GET', '/');\n\n    expect(azureHandler(context, event)).resolves.toBe(response);\n\n    expect(defaultGetHandler).toHaveBeenCalledWith(...getHandlerArguments);\n    expect(defaultServerlessHandler).toHaveBeenCalledWith(\n      event,\n      context,\n      undefined,\n    );\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(context.done).toBeUndefined();\n    expect(context.res).toBeUndefined();\n  });\n\n  it('should prefer context log method when send default logger', () => {\n    const event = createHttpTriggerEvent('GET', '/');\n    const context = createHttpTriggerContext('GET', '/');\n\n    const defaultServerlessHandler = vitest.fn(() => Promise.resolve(response));\n    const defaultGetHandler = vitest\n      .spyOn(DefaultHandler.prototype, 'getHandler')\n      .mockImplementation(() => defaultServerlessHandler);\n\n    const getHandlerArguments = [\n      app,\n      mockFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n    ] as const;\n\n    const azureHandler = azureHandlerFactory.getHandler(\n      ...getHandlerArguments,\n      createDefaultLogger(),\n    );\n\n    expect(azureHandler(context, event)).resolves.toBe(response);\n\n    expect(defaultGetHandler).toHaveBeenCalledWith(\n      ...getHandlerArguments,\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect.objectContaining({ error: context.log.error }),\n    );\n    expect(defaultServerlessHandler).toHaveBeenCalledWith(\n      event,\n      context,\n      undefined,\n    );\n  });\n\n  it('should prefer default log method when send false to useContextLogWhenInternalLogger option', () => {\n    const event = createHttpTriggerEvent('GET', '/');\n    const context = createHttpTriggerContext('GET', '/');\n\n    const defaultServerlessHandler = vitest.fn(() => Promise.resolve(response));\n    const defaultGetHandler = vitest\n      .spyOn(DefaultHandler.prototype, 'getHandler')\n      .mockImplementation(() => defaultServerlessHandler);\n\n    const log = createDefaultLogger();\n\n    const getHandlerArguments = [\n      app,\n      mockFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      log,\n    ] as const;\n\n    const azureHandler = new AzureHandler<null, HttpRequest, any, any, any>({\n      useContextLogWhenInternalLogger: false,\n    }).getHandler(...getHandlerArguments);\n\n    expect(azureHandler(context, event)).resolves.toBe(response);\n\n    expect(defaultGetHandler).toHaveBeenCalledWith(...getHandlerArguments);\n    expect(defaultServerlessHandler).toHaveBeenCalledWith(\n      event,\n      context,\n      undefined,\n    );\n  });\n});\n"
  },
  {
    "path": "test/handlers/default.handler.spec.ts",
    "content": "import { describe, expect, it, vitest } from 'vitest';\nimport {\n  type AdapterContract,\n  type ILogger,\n  NO_OP,\n  getCurrentInvoke,\n} from '../../src';\nimport { ApiGatewayV2Adapter } from '../../src/adapters/aws';\nimport { DefaultHandler } from '../../src/handlers/default';\nimport { PromiseResolver } from '../../src/resolvers/promise';\nimport { createApiGatewayV2 } from '../adapters/aws/utils/api-gateway-v2';\nimport { FrameworkMock } from '../mocks/framework.mock';\n\ndescribe('DefaultHandler', () => {\n  const defaultHandler = new DefaultHandler();\n\n  const app = null;\n  const response = { batata: true };\n  const apiGatewayAdapter = new ApiGatewayV2Adapter();\n  const adapters = [apiGatewayAdapter] as AdapterContract<any, any, any>[];\n  const resolver = new PromiseResolver();\n  const binarySettings = { contentEncodings: [], contentTypes: [] };\n  const respondWithErrors = true;\n  const executeLog = (_, fn) => typeof fn === 'function' && fn();\n  const logger: ILogger = {\n    debug: vitest.fn(executeLog),\n    error: vitest.fn(executeLog),\n    verbose: vitest.fn(executeLog),\n    info: vitest.fn(executeLog),\n    warn: vitest.fn(executeLog),\n  };\n\n  it('should forward and return the response from a request with different status', async () => {\n    const options: [statusCode: number][] = [[200], [400]];\n\n    for (const [statusCode] of options) {\n      const framework = new FrameworkMock(statusCode, response);\n\n      const handler = defaultHandler.getHandler(\n        app,\n        framework,\n        adapters,\n        resolver,\n        binarySettings,\n        respondWithErrors,\n        logger,\n      );\n\n      const event = createApiGatewayV2('GET', '/users', {}, { test: 'true' });\n      const context = { test: Symbol('unique') };\n\n      const result = await handler(event, context, NO_OP);\n\n      expect(getCurrentInvoke()).toHaveProperty('event', event);\n      expect(getCurrentInvoke()).toHaveProperty('context', context);\n\n      expect(logger.debug).toHaveBeenNthCalledWith(\n        1,\n        'SERVERLESS_ADAPTER:PROXY',\n        expect.any(Function),\n      );\n\n      expect(logger.debug).toHaveBeenNthCalledWith(\n        2,\n        'SERVERLESS_ADAPTER:RESOLVED_ADAPTER_NAME: ',\n        apiGatewayAdapter.getAdapterName(),\n      );\n\n      expect(logger.debug).toHaveBeenNthCalledWith(\n        3,\n        'SERVERLESS_ADAPTER:FORWARD_REQUEST_TO_FRAMEWORK:REQUEST_VALUES',\n        expect.any(Function),\n      );\n\n      expect(logger.debug).toHaveBeenNthCalledWith(\n        4,\n        'SERVERLESS_ADAPTER:FORWARD_REQUEST_TO_FRAMEWORK:RESPONSE',\n        expect.any(Function),\n      );\n\n      expect(logger.debug).toHaveBeenNthCalledWith(\n        5,\n        'SERVERLESS_ADAPTER:FORWARD_RESPONSE:EVENT_SOURCE_RESPONSE_PARAMS',\n        expect.any(Function),\n      );\n\n      expect(logger.debug).toHaveBeenNthCalledWith(\n        6,\n        'SERVERLESS_ADAPTER:FORWARD_RESPONSE:EVENT_SOURCE_RESPONSE',\n        expect.any(Function),\n      );\n\n      expect(result).toHaveProperty('headers', {\n        'content-type': 'application/json',\n      });\n      expect(result).toHaveProperty('isBase64Encoded', false);\n      expect(result).toHaveProperty('statusCode', statusCode);\n      expect(result).toHaveProperty('body', JSON.stringify(response));\n    }\n  });\n\n  it('should forward and return the response from a request with base64 encoding', async () => {\n    const framework = new FrameworkMock(200, response);\n\n    const handler = defaultHandler.getHandler(\n      app,\n      framework,\n      adapters,\n      resolver,\n      { isBinary: () => true },\n      respondWithErrors,\n      logger,\n    );\n\n    const event = createApiGatewayV2('GET', '/users', {}, { test: 'true' });\n    const context = { test: Symbol('unique') };\n\n    const result = await handler(event, context, NO_OP);\n\n    expect(result).toHaveProperty('headers', {\n      'content-type': 'application/json',\n    });\n    expect(result).toHaveProperty('isBase64Encoded', true);\n    expect(result).toHaveProperty('statusCode', 200);\n    expect(result).toHaveProperty(\n      'body',\n      Buffer.from(JSON.stringify(response)).toString('base64'),\n    );\n  });\n\n  it('should forward and return the response from a request with empty body', async () => {\n    const framework = new FrameworkMock(200, response);\n\n    const handler = defaultHandler.getHandler(\n      app,\n      framework,\n      adapters,\n      resolver,\n      { isBinary: () => true },\n      respondWithErrors,\n      logger,\n    );\n\n    const event = createApiGatewayV2('GET', '/users', undefined, {\n      test: 'true',\n    });\n    const context = { test: Symbol('unique') };\n\n    const result = await handler(event, context, NO_OP);\n\n    expect(result).toHaveProperty('headers', {\n      'content-type': 'application/json',\n    });\n    expect(result).toHaveProperty('isBase64Encoded', true);\n    expect(result).toHaveProperty('statusCode', 200);\n    expect(result).toHaveProperty(\n      'body',\n      Buffer.from(JSON.stringify(response)).toString('base64'),\n    );\n  });\n});\n"
  },
  {
    "path": "test/handlers/digital-ocean.handler.spec.ts",
    "content": "import { describe, expect, it, vitest } from 'vitest';\nimport { type ILogger } from '../../src';\nimport { HttpFunctionAdapter } from '../../src/adapters/digital-ocean';\nimport { DefaultHandler } from '../../src/handlers/default';\nimport { DigitalOceanHandler } from '../../src/handlers/digital-ocean';\nimport { PromiseResolver } from '../../src/resolvers/promise';\nimport { FrameworkMock } from '../mocks/framework.mock';\nimport { createHttpFunctionEvent } from '../adapters/digital-ocean/utils/http-function';\nimport type { DigitalOceanHttpEvent } from '../../src/@types/digital-ocean';\n\ndescribe(DigitalOceanHandler.name, () => {\n  const azureHandlerFactory = new DigitalOceanHandler<\n    null,\n    DigitalOceanHttpEvent,\n    any,\n    any\n  >();\n\n  const app = null;\n  const response = { batata: true };\n  const mockFramework = new FrameworkMock(200, response);\n  const adapter = new HttpFunctionAdapter();\n  const adapters = [adapter];\n  const resolver = new PromiseResolver();\n  const binarySettings = { contentEncodings: [], contentTypes: [] };\n  const respondWithErrors = true;\n  const logger: ILogger = {\n    debug: vitest.fn(),\n    error: vitest.fn(),\n    verbose: vitest.fn(),\n    info: vitest.fn(),\n    warn: vitest.fn(),\n  };\n\n  it('should call default handler with correct params', () => {\n    const defaultServerlessHandler = vitest.fn(() => Promise.resolve(response));\n    const defaultGetHandler = vitest\n      .spyOn(DefaultHandler.prototype, 'getHandler')\n      .mockImplementation(() => defaultServerlessHandler);\n\n    const getHandlerArguments = [\n      app,\n      mockFramework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    ] as const;\n\n    const azureHandler = azureHandlerFactory.getHandler(...getHandlerArguments);\n\n    const event = createHttpFunctionEvent('GET', '/');\n\n    expect(azureHandler(event)).resolves.toBe(response);\n\n    expect(defaultGetHandler).toHaveBeenCalledWith(...getHandlerArguments);\n    expect(defaultServerlessHandler).toHaveBeenCalledWith(\n      event,\n      undefined,\n      undefined,\n    );\n  });\n});\n"
  },
  {
    "path": "test/handlers/gcp.handler.spec.ts",
    "content": "import type { IncomingMessage, ServerResponse } from 'http';\nimport { describe, expect, it, vitest } from 'vitest';\nimport { type FrameworkContract } from '../../src';\nimport { GCPHandler } from '../../src/handlers/gcp';\nimport { FrameworkMock } from '../mocks/framework.mock';\n\nclass TestGCPHandler<TApp> extends GCPHandler<TApp> {\n  public override onRequestCallback(\n    app: TApp,\n    framework: FrameworkContract<TApp>,\n  ): (req: IncomingMessage, res: ServerResponse) => void | Promise<void> {\n    return super.onRequestCallback(app, framework);\n  }\n}\n\ndescribe(GCPHandler.name, () => {\n  it('should register the callback to the library', () => {\n    const functionName = 'test';\n    const gcpHandler = new TestGCPHandler(functionName);\n    const mockFramework = new FrameworkMock(204, {});\n\n    const mockedData = 'Mocked' as any;\n    const mockedFn = () => mockedData;\n\n    vitest.mock('@google-cloud/functions-framework', () => ({\n      http: (name, fn) => {\n        expect(name).toEqual('test');\n        expect(fn).toEqual('Mocked');\n      },\n    }));\n\n    vitest.spyOn(gcpHandler, 'onRequestCallback').mockImplementation(mockedFn);\n\n    const handler = gcpHandler.getHandler(null, mockFramework);\n\n    expect(handler).toEqual(mockedData);\n  });\n});\n"
  },
  {
    "path": "test/handlers/http-firebase-v2.handler.spec.ts",
    "content": "import type { HttpsOptions } from 'firebase-functions/v2/https';\nimport { describe, expect, it, vitest } from 'vitest';\nimport {\n  type FrameworkContract,\n  ServerlessRequest,\n  ServerlessResponse,\n  waitForStreamComplete,\n} from '../../src';\nimport { HttpFirebaseV2Handler } from '../../src/handlers/firebase';\nimport { FrameworkMock } from '../mocks/framework.mock';\n\ndescribe(HttpFirebaseV2Handler.name, () => {\n  it('should forward correctly the request to framework', async () => {\n    const handlerFactory = new HttpFirebaseV2Handler();\n\n    const method = 'POST';\n    const url = '/users/batata';\n    const headers = { 'Content-Type': 'application/json' };\n    const remoteAddress = '168.16.0.1';\n    const body = Buffer.from('{\"test\": true}', 'utf-8');\n\n    const request = new ServerlessRequest({\n      method,\n      url,\n      headers,\n      remoteAddress,\n      body,\n    });\n\n    const response = new ServerlessResponse({\n      method,\n    });\n\n    const responseBody = { batata: true };\n    const responseStatus = 200;\n    const framework = new FrameworkMock(responseStatus, responseBody);\n\n    const handler = handlerFactory.getHandler(null, framework);\n\n    handler(request, response);\n\n    await waitForStreamComplete(response);\n\n    expect(response.statusCode).toBe(responseStatus);\n    expect(ServerlessResponse.body(response).toString()).toStrictEqual(\n      JSON.stringify(responseBody),\n    );\n  });\n\n  it('should handle weird body types', () => {\n    const handlerFactory = new HttpFirebaseV2Handler();\n\n    const method = 'POST';\n    const url = '/users/batata';\n    const headers = { 'Content-Type': 'application/json' };\n    const remoteAddress = '168.16.0.1';\n    const options = [{ potato: true }, [{ test: true }]];\n\n    for (const option of options) {\n      const request = new ServerlessRequest({\n        method,\n        url,\n        headers,\n        remoteAddress,\n        body: option as any,\n      });\n\n      const response = new ServerlessResponse({\n        method,\n      });\n\n      const framework: FrameworkContract<unknown> = {\n        // eslint-disable-next-line @typescript-eslint/no-misused-promises\n        sendRequest: vitest.fn(\n          async (\n            _app: null,\n            req: ServerlessRequest,\n            res: ServerlessResponse,\n          ) => {\n            expect(req.body?.toString()).toEqual(JSON.stringify(option));\n            expect(req.headers['content-length']).toEqual(\n              Buffer.byteLength(JSON.stringify(option)).toString(),\n            );\n\n            req.pipe(res);\n\n            await waitForStreamComplete(res);\n\n            expect(ServerlessResponse.body(res).toString()).toEqual(\n              JSON.stringify(option),\n            );\n          },\n        ),\n      };\n\n      const handler = handlerFactory.getHandler(null, framework);\n\n      handler(request, response);\n    }\n  });\n\n  it('should forward the properties to https.onRequest', () => {\n    const options: HttpsOptions = {\n      concurrency: 400,\n    };\n    const factory = new HttpFirebaseV2Handler(options);\n\n    const spyMethod = vitest.spyOn(factory, 'onRequestWithOptions' as any);\n\n    factory.getHandler(null, new FrameworkMock(200, {}));\n\n    expect(spyMethod).toHaveBeenCalledWith(options, expect.any(Function));\n  });\n});\n"
  },
  {
    "path": "test/handlers/http-firebase-v2.sdk-v5.handler.spec.ts",
    "content": "import type { HttpsOptions } from 'firebase-functions/v2/https';\nimport { describe, expect, it, vitest } from 'vitest';\nimport {\n  type FrameworkContract,\n  ServerlessRequest,\n  ServerlessResponse,\n  waitForStreamComplete,\n} from '../../src';\nimport { HttpFirebaseV2Handler } from '../../src/handlers/firebase';\nimport { FrameworkMock } from '../mocks/framework.mock';\n\nvitest.mock('firebase-functions/v2', async () => {\n  // eslint-disable-next-line import/no-unresolved\n  return await import('firebase-functions-v5/v2');\n});\n\ndescribe(HttpFirebaseV2Handler.name, () => {\n  it('should forward correctly the request to framework', async () => {\n    const handlerFactory = new HttpFirebaseV2Handler();\n\n    const method = 'POST';\n    const url = '/users/batata';\n    const headers = { 'Content-Type': 'application/json' };\n    const remoteAddress = '168.16.0.1';\n    const body = Buffer.from('{\"test\": true}', 'utf-8');\n\n    const request = new ServerlessRequest({\n      method,\n      url,\n      headers,\n      remoteAddress,\n      body,\n    });\n\n    const response = new ServerlessResponse({\n      method,\n    });\n\n    const responseBody = { batata: true };\n    const responseStatus = 200;\n    const framework = new FrameworkMock(responseStatus, responseBody);\n\n    const handler = handlerFactory.getHandler(null, framework);\n\n    handler(request, response);\n\n    await waitForStreamComplete(response);\n\n    expect(response.statusCode).toBe(responseStatus);\n    expect(ServerlessResponse.body(response).toString()).toStrictEqual(\n      JSON.stringify(responseBody),\n    );\n  });\n\n  it('should handle weird body types', () => {\n    const handlerFactory = new HttpFirebaseV2Handler();\n\n    const method = 'POST';\n    const url = '/users/batata';\n    const headers = { 'Content-Type': 'application/json' };\n    const remoteAddress = '168.16.0.1';\n    const options = [{ potato: true }, [{ test: true }]];\n\n    for (const option of options) {\n      const request = new ServerlessRequest({\n        method,\n        url,\n        headers,\n        remoteAddress,\n        body: option as any,\n      });\n\n      const response = new ServerlessResponse({\n        method,\n      });\n\n      const framework: FrameworkContract<unknown> = {\n        // eslint-disable-next-line @typescript-eslint/no-misused-promises\n        sendRequest: vitest.fn(\n          async (\n            _app: null,\n            req: ServerlessRequest,\n            res: ServerlessResponse,\n          ) => {\n            expect(req.body?.toString()).toEqual(JSON.stringify(option));\n            expect(req.headers['content-length']).toEqual(\n              Buffer.byteLength(JSON.stringify(option)).toString(),\n            );\n\n            req.pipe(res);\n\n            await waitForStreamComplete(res);\n\n            expect(ServerlessResponse.body(res).toString()).toEqual(\n              JSON.stringify(option),\n            );\n          },\n        ),\n      };\n\n      const handler = handlerFactory.getHandler(null, framework);\n\n      handler(request, response);\n    }\n  });\n\n  it('should forward the properties to https.onRequest', () => {\n    const options: HttpsOptions = {\n      concurrency: 400,\n    };\n    const factory = new HttpFirebaseV2Handler(options);\n\n    const spyMethod = vitest.spyOn(factory, 'onRequestWithOptions' as any);\n\n    factory.getHandler(null, new FrameworkMock(200, {}));\n\n    expect(spyMethod).toHaveBeenCalledWith(options, expect.any(Function));\n  });\n});\n"
  },
  {
    "path": "test/handlers/http-firebase-v2.sdk-v6.handler.spec.ts",
    "content": "import type { HttpsOptions } from 'firebase-functions/v2/https';\nimport { describe, expect, it, vitest } from 'vitest';\nimport {\n  type FrameworkContract,\n  ServerlessRequest,\n  ServerlessResponse,\n  waitForStreamComplete,\n} from '../../src';\nimport { HttpFirebaseV2Handler } from '../../src/handlers/firebase';\nimport { FrameworkMock } from '../mocks/framework.mock';\n\nvitest.mock('firebase-functions/v2', async () => {\n  // eslint-disable-next-line import/no-unresolved\n  return await import('firebase-functions-v6/v2');\n});\n\ndescribe(HttpFirebaseV2Handler.name, () => {\n  it('should forward correctly the request to framework', async () => {\n    const handlerFactory = new HttpFirebaseV2Handler();\n\n    const method = 'POST';\n    const url = '/users/batata';\n    const headers = { 'Content-Type': 'application/json' };\n    const remoteAddress = '168.16.0.1';\n    const body = Buffer.from('{\"test\": true}', 'utf-8');\n\n    const request = new ServerlessRequest({\n      method,\n      url,\n      headers,\n      remoteAddress,\n      body,\n    });\n\n    const response = new ServerlessResponse({\n      method,\n    });\n\n    const responseBody = { batata: true };\n    const responseStatus = 200;\n    const framework = new FrameworkMock(responseStatus, responseBody);\n\n    const handler = handlerFactory.getHandler(null, framework);\n\n    handler(request, response);\n\n    await waitForStreamComplete(response);\n\n    expect(response.statusCode).toBe(responseStatus);\n    expect(ServerlessResponse.body(response).toString()).toStrictEqual(\n      JSON.stringify(responseBody),\n    );\n  });\n\n  it('should handle weird body types', () => {\n    const handlerFactory = new HttpFirebaseV2Handler();\n\n    const method = 'POST';\n    const url = '/users/batata';\n    const headers = { 'Content-Type': 'application/json' };\n    const remoteAddress = '168.16.0.1';\n    const options = [{ potato: true }, [{ test: true }]];\n\n    for (const option of options) {\n      const request = new ServerlessRequest({\n        method,\n        url,\n        headers,\n        remoteAddress,\n        body: option as any,\n      });\n\n      const response = new ServerlessResponse({\n        method,\n      });\n\n      const framework: FrameworkContract<unknown> = {\n        // eslint-disable-next-line @typescript-eslint/no-misused-promises\n        sendRequest: vitest.fn(\n          async (\n            _app: null,\n            req: ServerlessRequest,\n            res: ServerlessResponse,\n          ) => {\n            expect(req.body?.toString()).toEqual(JSON.stringify(option));\n            expect(req.headers['content-length']).toEqual(\n              Buffer.byteLength(JSON.stringify(option)).toString(),\n            );\n\n            req.pipe(res);\n\n            await waitForStreamComplete(res);\n\n            expect(ServerlessResponse.body(res).toString()).toEqual(\n              JSON.stringify(option),\n            );\n          },\n        ),\n      };\n\n      const handler = handlerFactory.getHandler(null, framework);\n\n      handler(request, response);\n    }\n  });\n\n  it('should forward the properties to https.onRequest', () => {\n    const options: HttpsOptions = {\n      concurrency: 400,\n    };\n    const factory = new HttpFirebaseV2Handler(options);\n\n    const spyMethod = vitest.spyOn(factory, 'onRequestWithOptions' as any);\n\n    factory.getHandler(null, new FrameworkMock(200, {}));\n\n    expect(spyMethod).toHaveBeenCalledWith(options, expect.any(Function));\n  });\n});\n"
  },
  {
    "path": "test/handlers/http-firebase.handler.spec.ts",
    "content": "import { describe, expect, it, vitest } from 'vitest';\nimport type { Request, Response } from 'express';\nimport {\n  type FrameworkContract,\n  ServerlessRequest,\n  ServerlessResponse,\n  waitForStreamComplete,\n} from '../../src';\nimport { HttpFirebaseHandler } from '../../src/handlers/firebase';\nimport { FrameworkMock } from '../mocks/framework.mock';\n\ndescribe(HttpFirebaseHandler.name, () => {\n  it('should forward correctly the request to framework', async () => {\n    const handlerFactory = new HttpFirebaseHandler<null>();\n\n    const method = 'POST';\n    const url = '/users/batata';\n    const headers = { 'Content-Type': 'application/json' };\n    const remoteAddress = '168.16.0.1';\n    const body = Buffer.from('{\"test\": true}', 'utf-8');\n\n    const request = new ServerlessRequest({\n      method,\n      url,\n      headers,\n      remoteAddress,\n      body,\n    });\n\n    const response = new ServerlessResponse({\n      method,\n    });\n\n    const responseBody = { batata: true };\n    const responseStatus = 200;\n    const framework = new FrameworkMock(responseStatus, responseBody);\n\n    const handler = handlerFactory.getHandler(null, framework);\n\n    handler(request as Request, response as unknown as Response);\n\n    await waitForStreamComplete(response);\n\n    expect(response.statusCode).toBe(responseStatus);\n    expect(ServerlessResponse.body(response).toString()).toStrictEqual(\n      JSON.stringify(responseBody),\n    );\n  });\n\n  it('should handle weird body types', () => {\n    const handlerFactory = new HttpFirebaseHandler();\n\n    const method = 'POST';\n    const url = '/users/batata';\n    const headers = { 'Content-Type': 'application/json' };\n    const remoteAddress = '168.16.0.1';\n    const options = [{ potato: true }, [{ test: true }]];\n\n    for (const option of options) {\n      const request = new ServerlessRequest({\n        method,\n        url,\n        headers,\n        remoteAddress,\n        body: option as any,\n      });\n\n      const response = new ServerlessResponse({\n        method,\n      });\n\n      const framework: FrameworkContract<unknown> = {\n        // eslint-disable-next-line @typescript-eslint/no-misused-promises\n        sendRequest: vitest.fn(\n          async (\n            _app: null,\n            req: ServerlessRequest,\n            res: ServerlessResponse,\n          ) => {\n            expect(req.body?.toString()).toEqual(JSON.stringify(option));\n            expect(req.headers['content-length']).toEqual(\n              Buffer.byteLength(JSON.stringify(option)).toString(),\n            );\n\n            req.pipe(res);\n\n            await waitForStreamComplete(res);\n\n            expect(ServerlessResponse.body(res).toString()).toEqual(\n              JSON.stringify(option),\n            );\n          },\n        ),\n      };\n\n      const handler = handlerFactory.getHandler(null, framework);\n\n      handler(request as Request, response as unknown as Response);\n    }\n  });\n});\n"
  },
  {
    "path": "test/handlers/huawei.handler.spec.ts",
    "content": "import { type Server, createServer } from 'node:http';\nimport supertest from 'supertest';\nimport { describe, expect, it, vitest } from 'vitest';\nimport { type ILogger } from '../../src';\nimport { DummyAdapter } from '../../src/adapters/dummy';\nimport {\n  DEFAULT_HUAWEI_LISTEN_PORT,\n  HttpHuaweiHandler,\n} from '../../src/handlers/huawei';\nimport { DummyResolver } from '../../src/resolvers/dummy';\nimport { FrameworkMock } from '../mocks/framework.mock';\n\ndescribe('HttpHuaweiHandler', () => {\n  const app = null;\n\n  const response = { batata: true };\n  const adapters = [new DummyAdapter()];\n  const resolver = new DummyResolver();\n  const binarySettings = { contentEncodings: [], contentTypes: [] };\n  const respondWithErrors = true;\n  const logger: ILogger = {\n    debug: vitest.fn(),\n    error: vitest.fn(),\n    verbose: vitest.fn(),\n    info: vitest.fn(),\n    warn: vitest.fn(),\n  };\n\n  it('should create correctly mocked server and test default constants', async () => {\n    const listenMock = vitest.fn();\n    const closeMock = vitest.fn(callback => callback());\n    const addEventListenerMock = vitest.fn();\n    const createServerMock = vitest.fn(\n      () =>\n        ({\n          listen: listenMock,\n          close: closeMock,\n          addEventListener: addEventListenerMock,\n        }) as unknown as Server,\n    );\n\n    const handlerFactory = new HttpHuaweiHandler({\n      httpServerFactory: createServerMock,\n    });\n\n    const framework = new FrameworkMock(200, response);\n\n    const dispose = handlerFactory.getHandler(\n      app,\n      framework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    expect(createServerMock).toHaveBeenCalledWith(expect.any(Function));\n    expect(listenMock).toHaveBeenCalledWith(\n      DEFAULT_HUAWEI_LISTEN_PORT,\n      expect.any(Function),\n    );\n\n    await expect(dispose()).resolves.toBeUndefined();\n\n    expect(closeMock).toHaveBeenCalled();\n    expect(logger.debug).toHaveBeenCalled();\n  });\n\n  async function waitUntilServerStarted(): Promise<void> {\n    await new Promise(resolve => setTimeout(resolve, 100));\n  }\n\n  it('should create correctly http server', async () => {\n    const handlerFactory = new HttpHuaweiHandler({\n      port: 0,\n    });\n    const framework = new FrameworkMock(200, response);\n\n    const dispose = handlerFactory.getHandler(\n      app,\n      framework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    await waitUntilServerStarted();\n\n    expect(logger.debug).toHaveBeenCalledWith(\n      expect.stringContaining('Server started'),\n    );\n\n    await expect(dispose()).resolves.toBeUndefined();\n\n    expect(logger.debug).toHaveBeenCalledWith(\n      expect.stringContaining('Disposing'),\n    );\n  });\n\n  it('should forward correctly the request to framework', async () => {\n    let httpServer!: Server;\n\n    const handlerFactory = new HttpHuaweiHandler({\n      port: 0,\n      httpServerFactory: requestListener => {\n        const server = createServer(requestListener);\n\n        httpServer = server;\n\n        return server;\n      },\n    });\n\n    const responseStatus = 200;\n    const framework = new FrameworkMock(responseStatus, response);\n\n    const dispose = handlerFactory.getHandler(\n      app,\n      framework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    const httpResponse = await supertest(httpServer).get('/').send();\n\n    expect(httpResponse.status).toBe(responseStatus);\n    expect(httpResponse.body).toStrictEqual(response);\n\n    await expect(dispose()).resolves.toBeUndefined();\n  });\n\n  it('should throw error if something wrong occours on dispose', async () => {\n    const error = new Error('something wrong occours');\n\n    const mockServer = {\n      listen: vitest.fn(),\n      close: vitest.fn(cb => cb(error)),\n    } as unknown as Server;\n\n    const handlerFactory = new HttpHuaweiHandler({\n      httpServerFactory: () => {\n        return mockServer;\n      },\n    });\n\n    const framework = new FrameworkMock(200, response);\n\n    const dispose = handlerFactory.getHandler(\n      app,\n      framework,\n      adapters,\n      resolver,\n      binarySettings,\n      respondWithErrors,\n      logger,\n    );\n\n    await waitUntilServerStarted();\n\n    await expect(async () => await dispose()).rejects.toThrow(error);\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(mockServer.close).toHaveBeenCalledWith(expect.any(Function));\n  });\n});\n"
  },
  {
    "path": "test/issues/alb-express-static/alb-express-static.spec.ts",
    "content": "import { resolve } from 'path';\nimport type { ALBResult } from 'aws-lambda';\nimport express from 'express';\nimport { describe, expect, it } from 'vitest';\nimport { ServerlessAdapter } from '../../../src';\nimport { AlbAdapter } from '../../../src/adapters/aws';\nimport { ExpressFramework } from '../../../src/frameworks/express';\nimport { DefaultHandler } from '../../../src/handlers/default';\nimport { PromiseResolver } from '../../../src/resolvers/promise';\nimport { createAlbEvent } from '../../adapters/aws/utils/alb-event';\n\ndescribe('ALB rejecting response when uses express.static because', () => {\n  it('returns some headers that are not string', async () => {\n    const app = express();\n\n    app.use(express.static(resolve(__dirname)));\n\n    const handler = ServerlessAdapter.new(app)\n      .setHandler(new DefaultHandler())\n      .setFramework(new ExpressFramework())\n      .setResolver(new PromiseResolver())\n      .addAdapter(new AlbAdapter())\n      .build();\n\n    const albEvent = createAlbEvent('GET', '/robots.txt');\n\n    const response = (await handler(albEvent, {})) as ALBResult;\n\n    for (const header of Object.keys(response.headers || {})) {\n      expect(`typeof ${header}: ${typeof response.headers![header]}`).toBe(\n        `typeof ${header}: string`,\n      );\n    }\n  });\n});\n"
  },
  {
    "path": "test/issues/alb-express-static/robots.txt",
    "content": "test\n"
  },
  {
    "path": "test/issues/issue-165/transfer-encoding-chunked-support.spec.ts",
    "content": "import { setTimeout } from 'timers/promises';\nimport { Readable } from 'node:stream';\nimport { describe, expect, it } from 'vitest';\nimport express from 'express';\nimport fastify from 'fastify';\nimport polka from 'polka';\nimport { ServerlessAdapter } from '../../../src';\nimport { DefaultHandler } from '../../../src/handlers/default';\nimport { PromiseResolver } from '../../../src/resolvers/promise';\nimport { ExpressFramework } from '../../../src/frameworks/express';\nimport { AlbAdapter } from '../../../src/adapters/aws';\nimport { createAlbEvent } from '../../adapters/aws/utils/alb-event';\nimport { FastifyFramework } from '../../../src/frameworks/fastify';\nimport { PolkaFramework } from '../../../src/frameworks/polka';\n\nconst expectedResult = 'INITIAL PAYLOAD RESPONSE\\nFINAL PAYLOAD RESPONSE\\n';\n\ndescribe('Issue 165: cannot handle transfer-encoding: chunked', () => {\n  it('express: should handle transfer-encoding: chunked', async () => {\n    const app = express();\n\n    // eslint-disable-next-line @typescript-eslint/no-misused-promises\n    app.get('/chunked-response', async (_req, res) => {\n      // Send headers right away\n      res.setHeader('Content-Type', 'text/plain');\n      res.setHeader('Transfer-Encoding', 'chunked');\n      res.status(200);\n\n      res.write('INITIAL PAYLOAD RESPONSE\\n');\n      await setTimeout(50);\n      res.end('FINAL PAYLOAD RESPONSE\\n');\n    });\n\n    const albEvent = createAlbEvent('GET', '/chunked-response');\n\n    const handler = ServerlessAdapter.new(app)\n      .setHandler(new DefaultHandler())\n      .setFramework(new ExpressFramework())\n      .setResolver(new PromiseResolver())\n      .addAdapter(new AlbAdapter())\n      .build();\n\n    const result = await handler(albEvent, {});\n\n    expect(result.body).toEqual(expectedResult);\n    expect(result.headers['content-length'], expectedResult.length.toString());\n  });\n\n  it('fastify: should handle transfer-encoding: chunked', async () => {\n    const app = fastify();\n\n    // eslint-disable-next-line @typescript-eslint/no-misused-promises\n    app.get('/chunked-response', async (_req, res) => {\n      // Send headers right away\n      res.type('text/plain');\n      res.header('Transfer-Encoding', 'chunked');\n      res.status(200);\n\n      const buffer = new Readable();\n      buffer._read = () => {};\n\n      res.send(buffer);\n\n      buffer.push('INITIAL PAYLOAD RESPONSE\\n');\n      await setTimeout(50);\n      buffer.push('FINAL PAYLOAD RESPONSE\\n');\n      buffer.push(null);\n    });\n\n    const albEvent = createAlbEvent('GET', '/chunked-response');\n\n    const handler = ServerlessAdapter.new(app)\n      .setHandler(new DefaultHandler())\n      .setFramework(new FastifyFramework())\n      .setResolver(new PromiseResolver())\n      .addAdapter(new AlbAdapter())\n      .build();\n\n    const result = await handler(albEvent, {});\n\n    expect(result.body).toEqual(expectedResult);\n    expect(result.headers['content-length'], expectedResult.length.toString());\n  });\n\n  it('polka: should handle transfer-encoding: chunked', async () => {\n    const app = polka();\n\n    // eslint-disable-next-line @typescript-eslint/no-misused-promises\n    app.get('/chunked-response', async (_req, res) => {\n      // Send headers right away\n      res.setHeader('Content-Type', 'text/plain');\n      res.setHeader('Transfer-Encoding', 'chunked');\n      res.statusCode = 200;\n\n      res.write('INITIAL PAYLOAD RESPONSE\\n');\n      await setTimeout(50);\n      res.end('FINAL PAYLOAD RESPONSE\\n');\n    });\n\n    const albEvent = createAlbEvent('GET', '/chunked-response');\n\n    const handler = ServerlessAdapter.new(app)\n      .setHandler(new DefaultHandler())\n      .setFramework(new PolkaFramework())\n      .setResolver(new PromiseResolver())\n      .addAdapter(new AlbAdapter())\n      .build();\n\n    const result = await handler(albEvent, {});\n\n    expect(result.body).toEqual(expectedResult);\n    expect(result.headers['content-length'], expectedResult.length.toString());\n  });\n});\n"
  },
  {
    "path": "test/mocks/framework.mock.ts",
    "content": "//#region Imports\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport { ObjectReadableMock } from 'stream-mock';\nimport { type FrameworkContract } from '../../src';\n\n//#endregion\n\n/**\n * The class that represents a mock for framework that forward the request body to the response.\n *\n * @internal\n */\nexport class FrameworkMock implements FrameworkContract<null> {\n  //#region Constructor\n\n  /**\n   * Construtor padrão\n   */\n  constructor(\n    protected readonly statusCode: number,\n    protected readonly mockedResponseData: object,\n  ) {}\n\n  //#endregion\n\n  /**\n   * {@inheritDoc}\n   */\n  public sendRequest(\n    _: null,\n    _request: IncomingMessage,\n    response: ServerResponse,\n  ): void {\n    const writableOutput = new ObjectReadableMock(\n      [Buffer.from(JSON.stringify(this.mockedResponseData))],\n      {\n        objectMode: true,\n      },\n    );\n\n    response.statusCode = this.statusCode;\n    response.setHeader('content-type', 'application/json');\n\n    writableOutput.pipe(response);\n  }\n}\n"
  },
  {
    "path": "test/network/request.spec.ts",
    "content": "import { describe, expect, it, vitest } from 'vitest';\nimport { NO_OP, ServerlessRequest } from '../../src';\n\ndescribe('ServerlessRequest', () => {\n  it('should can create serverless request from parameters of constructor', () => {\n    const method = 'POST';\n    const url = '/users/batata';\n    const headers = { 'Content-Type': 'application/json' };\n    const remoteAddress = '168.16.0.1';\n    const body = Buffer.from('{\"test\": true}', 'utf-8');\n\n    const request = new ServerlessRequest({\n      method,\n      url,\n      headers,\n      remoteAddress,\n      body,\n    });\n\n    expect(request).toHaveProperty('statusCode', 200);\n    expect(request).toHaveProperty('statusMessage', 'OK');\n    expect(request).toHaveProperty('url', url);\n    expect(request).toHaveProperty('headers', headers);\n    expect(request).toHaveProperty('ip', remoteAddress);\n    expect(request).toHaveProperty('body', body);\n    expect(request).toHaveProperty('complete', true);\n    expect(request).toHaveProperty('httpVersion', '1.1');\n    expect(request).toHaveProperty('httpVersionMajor', 1);\n    expect(request).toHaveProperty('httpVersionMinor', 1);\n    expect(request.socket).toHaveProperty('encrypted', true);\n    expect(request.socket).toHaveProperty('readable', true);\n    expect(request.socket).toHaveProperty('remoteAddress', remoteAddress);\n    expect(request.socket).toHaveProperty('end', NO_OP);\n    expect(request.socket).toHaveProperty('destroy', NO_OP);\n    expect(request.socket.address()).toHaveProperty('port', 443);\n  });\n\n  it('should push body property when call _read', () => {\n    const method = 'POST';\n    const url = '/users/batata';\n    const headers = { 'Content-Type': 'application/json' };\n    const remoteAddress = '168.16.0.1';\n    const body = Buffer.from('{\"random\": 2323}', 'utf-8');\n\n    const request = new ServerlessRequest({\n      method,\n      url,\n      headers,\n      remoteAddress,\n      body,\n    });\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    request.push = vitest.fn(request.push);\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    request._read = vitest.fn(request._read);\n\n    request._read(Math.random());\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(request.push).toHaveBeenNthCalledWith(1, body);\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(request.push).toHaveBeenNthCalledWith(2, null);\n  });\n});\n"
  },
  {
    "path": "test/network/response.spec.ts",
    "content": "import { ObjectReadableMock } from 'stream-mock';\nimport { describe, expect, it, vitest } from 'vitest';\nimport {\n  ServerlessRequest,\n  ServerlessResponse,\n  waitForStreamComplete,\n} from '../../src';\n\ndescribe('ServerlessResponse', () => {\n  it('should can create serverless response from parameters of constructor', () => {\n    const method = 'POST';\n\n    const response = new ServerlessResponse({\n      method,\n    });\n\n    expect(response).toHaveProperty('useChunkedEncodingByDefault', false);\n    expect(response).toHaveProperty('chunkedEncoding', false);\n    expect(response).toHaveProperty('writable', true);\n    expect(response).toHaveProperty('writableEnded', false);\n\n    const responseBody = ServerlessResponse.body(response);\n\n    expect(responseBody).toBeInstanceOf(Buffer);\n    expect(responseBody.length).toEqual(0);\n\n    const responseHeaders = ServerlessResponse.headers(response);\n\n    expect(Object.keys(responseHeaders).length).toEqual(0);\n\n    response.setHeader('test', 'testedValue');\n\n    const responseHeadersWithValue = ServerlessResponse.headers(response);\n\n    expect(responseHeadersWithValue).toHaveProperty('test', 'testedValue');\n\n    // we didn't have the header that we set before because this method\n    // get the value from headers inside the response instead from original implementation\n    expect(response.headers).not.toHaveProperty('test', 'testedValue');\n  });\n\n  it('should can create response from request', () => {\n    const defaultParams = {\n      method: 'GET',\n      headers: { test2: 'value2' },\n      url: '/values',\n    };\n\n    const request = new ServerlessRequest({\n      ...defaultParams,\n    });\n\n    const requestWithBody = new ServerlessRequest({\n      ...defaultParams,\n      body: Buffer.from('{\"test\": true}', 'utf-8'),\n    });\n\n    const requestWithBodyString = new ServerlessRequest({\n      ...defaultParams,\n      body: '{\"test\": true}' as any,\n    });\n\n    const requestWithUintArray = new ServerlessRequest({\n      ...defaultParams,\n      body: Uint8Array.from(\n        Array.from('{\"test\": true}').map(c => c.charCodeAt(0)),\n      ),\n    });\n\n    const requestHead = new ServerlessRequest({\n      ...defaultParams,\n      method: 'HEAD',\n    });\n\n    const requests: [\n      request: ServerlessRequest,\n      expectedLength: number,\n      hasBody: boolean,\n    ][] = [\n      [request, 0, true],\n      [requestWithBody, requestWithBody.body!.length, true],\n      [requestWithBodyString, requestWithBodyString.body!.length, true],\n      [requestWithUintArray, requestWithUintArray.body!.length, true],\n      [requestHead, 0, false],\n    ];\n\n    for (const [request, expectedLength, hasBody] of requests) {\n      const responseFrom = ServerlessResponse.from(request);\n\n      // why I have this test? Because of this line: https://github.com/nodejs/node/blob/master/lib/_http_server.js#L181\n      // the only way that I can use to check if method passed in request is working.\n      expect(responseFrom).toHaveProperty('_hasBody', hasBody);\n      expect(responseFrom).toHaveProperty(\n        'statusCode',\n        responseFrom.statusCode,\n      );\n      expect(responseFrom.headers).toHaveProperty(\n        'test2',\n        defaultParams.headers.test2,\n      );\n\n      const body = ServerlessResponse.body(responseFrom);\n\n      expect(body).toHaveLength(expectedLength);\n      expect(responseFrom).toHaveProperty('writable', true);\n      expect(responseFrom).toHaveProperty('writableEnded', true);\n\n      // In this case, when we use ServerlessResponse.from we set\n      // response headers instead setting original implementation,\n      // so, we have access to the headers by calling get headers property\n      expect(responseFrom.headers).toHaveProperty(\n        'test2',\n        defaultParams.headers.test2,\n      );\n    }\n  });\n\n  it('should can pipe response and return correct data', async () => {\n    const options: [\n      value: string | Buffer | Uint8Array,\n      expectedValue: string,\n    ][] = [\n      ['test', 'test'],\n      [Buffer.from('{\"yo\": true}', 'utf-8'), '{\"yo\": true}'],\n      [\n        Uint8Array.from(Array.from('{\"test\": true}').map(c => c.charCodeAt(0))),\n        '{\"test\": true}',\n      ],\n    ];\n\n    for (const [testedData, expectedValue] of options) {\n      const response = new ServerlessResponse({\n        method: 'GET',\n      });\n\n      const read = new ObjectReadableMock([testedData], {\n        objectMode: true,\n      });\n\n      read.pipe(response);\n\n      const waitedStream = await waitForStreamComplete(response);\n\n      expect(waitedStream).toBe(response);\n      expect(ServerlessResponse.body(response).toString('utf-8')).toBe(\n        expectedValue,\n      );\n    }\n  });\n\n  it('should cannot pipe response with invalid data', () => {\n    const options: any[] = [void 0, null];\n\n    for (const testedData of options) {\n      const response = new ServerlessResponse({\n        method: 'GET',\n      });\n\n      expect(() => response.connection!.write(testedData)).toThrowError(\n        'response.write()',\n      );\n\n      expect(() => response.connection!.write(testedData)).toThrowError(\n        'response.write()',\n      );\n    }\n\n    for (const testedData of options) {\n      const response = new ServerlessResponse({\n        method: 'GET',\n      });\n\n      response._header = null as any;\n\n      expect(() => response.connection!.write(testedData)).toThrowError(\n        'response.write()',\n      );\n    }\n  });\n\n  it('should call correctly the callback with valid data in response', () => {\n    const options = [\n      'test',\n      Buffer.from('testB', 'utf-8'),\n      Uint8Array.from(Array.from('{\"test\": true}').map(c => c.charCodeAt(0))),\n    ];\n\n    for (const testedData of options) {\n      const response = new ServerlessResponse({\n        method: 'GET',\n      });\n\n      response._header = null as any;\n\n      const callback = vitest.fn();\n\n      expect(() =>\n        response.connection!.write(testedData, callback),\n      ).not.toThrowError();\n\n      expect(callback).toHaveBeenCalled();\n    }\n  });\n\n  it('should write headers correctly in object when call writeHead', () => {\n    class MockServerlessResponse extends ServerlessResponse {\n      public override callNativeWriteHead(\n        statusCode: number,\n        statusMessage?: string | any | any[],\n        obj?: any | any[],\n      ): this {\n        return super.callNativeWriteHead(statusCode, statusMessage, obj);\n      }\n    }\n\n    const response = new MockServerlessResponse({\n      method: 'GET',\n    });\n\n    response.callNativeWriteHead = vitest.fn();\n    response.setHeader = vitest.fn();\n\n    expect(() => response.writeHead(200, { test1: 'true' })).not.toThrowError();\n    expect(() =>\n      response.writeHead(200, [{ test2: 'true' }, { test3: 'true' }]),\n    ).not.toThrowError();\n    expect(() =>\n      response.writeHead(200, 'test', { test4: 'true' }),\n    ).not.toThrowError();\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(response.setHeader).toHaveBeenCalledTimes(4);\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(response.setHeader).toHaveBeenNthCalledWith(1, 'test1', 'true');\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(response.setHeader).toHaveBeenNthCalledWith(2, 'test2', 'true');\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(response.setHeader).toHaveBeenNthCalledWith(3, 'test3', 'true');\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(response.setHeader).toHaveBeenNthCalledWith(4, 'test4', 'true');\n  });\n\n  it('should write headers correctly in object when call setHeader', () => {\n    const response = new ServerlessResponse({\n      method: 'GET',\n    });\n\n    response.setHeader('test', 'value');\n\n    expect(response.getHeaders()).toHaveProperty('test', 'value');\n\n    response._wroteHeader = true;\n\n    response.setHeader('test2', 'value');\n\n    expect(response.getHeaders()).not.toHaveProperty('test2', 'value');\n    expect(response.headers).toHaveProperty('test2', 'value');\n  });\n});\n"
  },
  {
    "path": "test/resolvers/aws-context.resolver.spec.ts",
    "content": "import type { Context } from 'aws-lambda';\nimport { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport type {\n  AdapterContract,\n  ILogger,\n  OnErrorProps,\n  ResolverProps,\n} from '../../src';\nimport { AwsContextResolver } from '../../src/resolvers/aws-context';\n\ndescribe(AwsContextResolver.name, () => {\n  let resolverFactory!: AwsContextResolver<unknown, unknown, unknown>;\n  let mockedContext!: Context;\n  let mockedLogger!: ILogger;\n  let mockedAdapter!: AdapterContract<unknown, unknown, unknown>;\n\n  function onContextResolve(task: () => void): void {\n    setTimeout(task, 200);\n  }\n\n  beforeEach(() => {\n    resolverFactory = new AwsContextResolver();\n\n    mockedContext = {\n      succeed: vitest.fn(),\n      fail: vitest.fn(),\n    } as unknown as Context;\n\n    mockedLogger = {\n      error: vitest.fn(),\n    } as unknown as ILogger;\n\n    mockedAdapter = {\n      onErrorWhileForwarding: vitest.fn(\n        ({\n          error,\n          delegatedResolver,\n          respondWithErrors,\n          log,\n          event,\n        }: OnErrorProps<any, any>) => {\n          expect(error).toBeInstanceOf(Error);\n          expect(delegatedResolver).toHaveProperty('succeed');\n          expect(delegatedResolver).toHaveProperty('fail');\n          expect(typeof respondWithErrors).toBe('boolean');\n          expect(log).toBe(mockedLogger);\n          expect(event).toBeDefined();\n\n          delegatedResolver.fail(error);\n        },\n      ),\n    } as unknown as AdapterContract<any, any, any>;\n  });\n\n  it('should call correctly the context when succeed', async () => {\n    const resolverProps: ResolverProps<any, any, Context, any> = {\n      log: mockedLogger,\n      respondWithErrors: false,\n      context: mockedContext,\n      event: {},\n      adapter: mockedAdapter,\n    };\n\n    const resolver = resolverFactory.createResolver(resolverProps);\n\n    const result = resolver.run(() => Promise.resolve(true));\n\n    expect(result).toBeUndefined();\n\n    await new Promise<void>(resolve => {\n      onContextResolve(() => {\n        expect(resolverProps.context.succeed).toHaveBeenCalledWith(true);\n\n        resolve();\n      });\n    });\n  });\n\n  it('should call correctly the context when fail', async () => {\n    const resolverProps: ResolverProps<any, any, Context, any> = {\n      log: mockedLogger,\n      respondWithErrors: false,\n      context: mockedContext,\n      event: {},\n      adapter: mockedAdapter,\n    };\n\n    const error = new Error('error on test');\n\n    const resolver = resolverFactory.createResolver(resolverProps);\n    const result = resolver.run(() => Promise.reject(error));\n\n    expect(result).toBeUndefined();\n\n    await new Promise<void>(resolve => {\n      onContextResolve(() => {\n        expect(resolverProps.log.error).toHaveBeenCalled();\n\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(resolverProps.adapter.onErrorWhileForwarding).toHaveBeenCalled();\n        expect(resolverProps.context.fail).toHaveBeenCalledWith(error);\n\n        resolve();\n      });\n    });\n  });\n\n  it('should return error when sending wrong arguments to build resolver', () => {\n    expect(() =>\n      resolverFactory.createResolver({\n        log: mockedLogger,\n        respondWithErrors: false,\n        adapter: mockedAdapter,\n        event: {},\n      }),\n    ).toThrowError();\n\n    expect(() =>\n      resolverFactory.createResolver({\n        log: mockedLogger,\n        respondWithErrors: false,\n        adapter: mockedAdapter,\n        context: {} as unknown as Context,\n        event: {},\n      }),\n    ).toThrowError();\n\n    expect(() =>\n      resolverFactory.createResolver({\n        log: mockedLogger,\n        respondWithErrors: false,\n        adapter: mockedAdapter,\n        context: {\n          succeed: undefined,\n          fail: vitest.fn(),\n        } as unknown as Context,\n        event: {},\n      }),\n    ).toThrowError();\n\n    expect(() =>\n      resolverFactory.createResolver({\n        log: mockedLogger,\n        respondWithErrors: false,\n        adapter: mockedAdapter,\n        context: {\n          succeed: vitest.fn(),\n          fail: undefined,\n        } as unknown as Context,\n        event: {},\n      }),\n    ).toThrowError();\n  });\n});\n"
  },
  {
    "path": "test/resolvers/callback.resolver.spec.ts",
    "content": "import { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport type {\n  AdapterContract,\n  ILogger,\n  OnErrorProps,\n  ResolverProps,\n} from '../../src';\nimport {\n  CallbackResolver,\n  type ServerlessCallback,\n} from '../../src/resolvers/callback';\n\ndescribe(CallbackResolver.name, () => {\n  let resolverFactory!: CallbackResolver<unknown, unknown, unknown>;\n  let mockedLogger!: ILogger;\n  let mockedAdapter!: AdapterContract<unknown, unknown, unknown>;\n\n  function onCallbackResolve(task: () => void): void {\n    setTimeout(task, 200);\n  }\n\n  beforeEach(() => {\n    resolverFactory = new CallbackResolver();\n\n    mockedLogger = {\n      error: vitest.fn(),\n    } as unknown as ILogger;\n\n    mockedAdapter = {\n      onErrorWhileForwarding: vitest.fn(\n        ({\n          error,\n          delegatedResolver,\n          respondWithErrors,\n          log,\n          event,\n        }: OnErrorProps<any, any>) => {\n          expect(error).toBeInstanceOf(Error);\n          expect(delegatedResolver).toHaveProperty('succeed');\n          expect(delegatedResolver).toHaveProperty('fail');\n          expect(typeof respondWithErrors).toBe('boolean');\n          expect(log).toBe(mockedLogger);\n          expect(event).toBeDefined();\n\n          delegatedResolver.fail(error);\n        },\n      ),\n    } as unknown as AdapterContract<any, any, any>;\n  });\n\n  it('should call correctly the callback when succeed', async () => {\n    const resolverProps: ResolverProps<\n      any,\n      any,\n      ServerlessCallback<any>,\n      any\n    > = {\n      log: mockedLogger,\n      respondWithErrors: false,\n      callback: vitest.fn(),\n      event: {},\n      adapter: mockedAdapter,\n    };\n\n    const resolver = resolverFactory.createResolver(resolverProps);\n\n    const result = resolver.run(() => Promise.resolve(true));\n\n    expect(result).toBeUndefined();\n\n    await new Promise<void>(resolve => {\n      onCallbackResolve(() => {\n        expect(resolverProps.callback).toHaveBeenCalledWith(null, true);\n\n        resolve();\n      });\n    });\n  });\n\n  it('should call correctly the callback when fail', async () => {\n    const resolverProps: ResolverProps<\n      any,\n      any,\n      ServerlessCallback<any>,\n      any\n    > = {\n      log: mockedLogger,\n      respondWithErrors: false,\n      callback: vitest.fn(),\n      event: {},\n      adapter: mockedAdapter,\n    };\n\n    const error = new Error('error on test');\n\n    const resolver = resolverFactory.createResolver(resolverProps);\n    const result = resolver.run(() => Promise.reject(error));\n\n    expect(result).toBeUndefined();\n\n    await new Promise<void>(resolve => {\n      onCallbackResolve(() => {\n        expect(resolverProps.log.error).toHaveBeenCalled();\n\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(resolverProps.adapter.onErrorWhileForwarding).toHaveBeenCalled();\n        expect(resolverProps.callback).toHaveBeenCalledWith(error, null);\n\n        resolve();\n      });\n    });\n  });\n\n  it('should return error when sending wrong arguments to build resolver', () => {\n    expect(() =>\n      resolverFactory.createResolver({\n        log: mockedLogger,\n        respondWithErrors: false,\n        adapter: mockedAdapter,\n        event: {},\n      }),\n    ).toThrowError();\n  });\n});\n"
  },
  {
    "path": "test/resolvers/dummy.resolver.spec.ts",
    "content": "import { describe, expect, it, vitest } from 'vitest';\nimport { DummyResolver } from '../../src/resolvers/dummy';\n\ndescribe(DummyResolver.name, () => {\n  it('should do nothing when called and return undefined', () => {\n    const resolver = new DummyResolver();\n\n    const task = vitest.fn();\n\n    resolver.createResolver().run(task);\n\n    expect(task).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "test/resolvers/promise.resolver.spec.ts",
    "content": "import { beforeEach, describe, expect, it, vitest } from 'vitest';\nimport type { Context } from 'aws-lambda';\nimport type {\n  AdapterContract,\n  ILogger,\n  OnErrorProps,\n  ResolverProps,\n} from '../../src';\nimport { PromiseResolver } from '../../src/resolvers/promise';\n\ndescribe(PromiseResolver.name, () => {\n  let resolverFactory!: PromiseResolver<\n    unknown,\n    unknown,\n    unknown,\n    unknown,\n    unknown\n  >;\n  let mockedContext!: Context;\n  let mockedLogger!: ILogger;\n  let mockedAdapter!: AdapterContract<unknown, unknown, unknown>;\n\n  beforeEach(() => {\n    resolverFactory = new PromiseResolver();\n\n    mockedContext = {\n      succeed: vitest.fn(),\n      fail: vitest.fn(),\n    } as unknown as Context;\n\n    mockedLogger = {\n      error: vitest.fn(),\n    } as unknown as ILogger;\n\n    mockedAdapter = {\n      onErrorWhileForwarding: vitest.fn(\n        ({\n          error,\n          delegatedResolver,\n          respondWithErrors,\n          log,\n          event,\n        }: OnErrorProps<any, any>) => {\n          expect(error).toBeInstanceOf(Error);\n          expect(delegatedResolver).toHaveProperty('succeed');\n          expect(delegatedResolver).toHaveProperty('fail');\n          expect(typeof respondWithErrors).toBe('boolean');\n          expect(log).toBe(mockedLogger);\n          expect(event).toBeDefined();\n\n          delegatedResolver.fail(error);\n        },\n      ),\n    } as unknown as AdapterContract<any, any, any>;\n  });\n\n  it('should call correctly the promise when succeed', async () => {\n    const resolverProps: ResolverProps<any, any, Context, any> = {\n      log: mockedLogger,\n      respondWithErrors: false,\n      event: {},\n      adapter: mockedAdapter,\n    };\n\n    const resolver = resolverFactory.createResolver(resolverProps);\n\n    const result = await resolver.run(() => Promise.resolve(true));\n\n    expect(result).toBe(true);\n  });\n\n  it('should call correctly the promise when fail', async () => {\n    const resolverProps: ResolverProps<any, any, Context, any> = {\n      log: mockedLogger,\n      respondWithErrors: false,\n      context: mockedContext,\n      event: {},\n      adapter: mockedAdapter,\n    };\n\n    const error = new Error('error on test');\n\n    const resolver = resolverFactory.createResolver(resolverProps);\n\n    await expect(resolver.run(() => Promise.reject(error))).rejects.toBe(error);\n\n    expect(resolverProps.log.error).toHaveBeenCalled();\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(resolverProps.adapter.onErrorWhileForwarding).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "test/serverless-adapter.spec.ts",
    "content": "import { describe, expect, it, vitest } from 'vitest';\nimport {\n  type BinarySettings,\n  DEFAULT_BINARY_CONTENT_TYPES,\n  DEFAULT_BINARY_ENCODINGS,\n  type HandlerContract,\n  NO_OP,\n  ServerlessAdapter,\n  createDefaultLogger,\n} from '../src';\nimport { ApiGatewayV2Adapter } from '../src/adapters/aws';\nimport * as logger from '../src/core/logger';\nimport { DefaultHandler } from '../src/handlers/default';\nimport { PromiseResolver } from '../src/resolvers/promise';\nimport { FrameworkMock } from './mocks/framework.mock';\n\ndescribe('ServerlessAdapter', () => {\n  it('should have correct default values', () => {\n    const defaultLoggerSymbol = Symbol('createDefaultLogger');\n\n    vitest\n      .spyOn(logger, 'createDefaultLogger')\n      .mockReturnValue(defaultLoggerSymbol as any);\n    const oldEnv = process.env;\n    vitest.resetModules();\n    process.env = { ...oldEnv, NODE_ENV: 'test' };\n\n    const adapter = ServerlessAdapter.new(null);\n\n    expect(adapter['binarySettings']).toHaveProperty(\n      'contentEncodings',\n      DEFAULT_BINARY_ENCODINGS,\n    );\n    expect(adapter['binarySettings']).toHaveProperty(\n      'contentTypes',\n      DEFAULT_BINARY_CONTENT_TYPES,\n    );\n    expect(adapter['respondWithErrors']).toEqual(false);\n    expect(adapter['log']).toEqual(defaultLoggerSymbol);\n    expect(adapter['adapters']).toHaveLength(0);\n    expect(adapter['framework']).toBeUndefined();\n    expect(adapter['resolver']).toBeUndefined();\n    expect(adapter['handler']).toBeUndefined();\n    expect(adapter['app']).toEqual(null);\n\n    vitest.resetModules();\n    process.env = { ...oldEnv, NODE_ENV: 'development' };\n    const developmentAdapter = ServerlessAdapter.new(null);\n\n    expect(developmentAdapter['respondWithErrors']).toEqual(true);\n  });\n\n  it('should can create a pipeline of handlers', () => {\n    const statusCode = 200;\n    const response = { body: true };\n    const app = null;\n\n    const mockedHandler: HandlerContract<any, any, any, any, any, any> = {\n      getHandler: vitest.fn(() => NO_OP),\n    };\n\n    const adapter = new ApiGatewayV2Adapter();\n    const logger = createDefaultLogger();\n    const respondWithErrors = false;\n    const resolver = new PromiseResolver();\n    const framework = new FrameworkMock(statusCode, response);\n    const binarySettings: BinarySettings = { isBinary: () => true };\n\n    const handler = ServerlessAdapter.new(app)\n      .setHandler(mockedHandler)\n      .setLogger(logger)\n      .setRespondWithErrors(respondWithErrors)\n      .setResolver(resolver)\n      .setFramework(framework)\n      .setBinarySettings(binarySettings)\n      .addAdapter(adapter)\n      .build();\n\n    expect(handler).toBe(NO_OP);\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(mockedHandler.getHandler).toHaveBeenCalledWith(\n      app,\n      framework,\n      [adapter],\n      resolver,\n      expect.objectContaining(binarySettings),\n      respondWithErrors,\n      logger,\n    );\n  });\n\n  it('should CANNOT set handler twice', () => {\n    const handler = new DefaultHandler();\n\n    expect(() =>\n      ServerlessAdapter.new(null)\n        .setHandler(handler)\n        .setRespondWithErrors(true)\n        .setHandler(handler),\n    ).toThrow('twice');\n  });\n\n  it('should CANNOT set framework twice', () => {\n    const framework = new FrameworkMock(200, {});\n\n    expect(() =>\n      ServerlessAdapter.new(null)\n        .setFramework(framework)\n        .setRespondWithErrors(true)\n        .setFramework(framework),\n    ).toThrow('twice');\n  });\n\n  it('should CANNOT set resolver twice', () => {\n    const resolver = new PromiseResolver();\n\n    expect(() =>\n      ServerlessAdapter.new(null)\n        .setResolver(resolver)\n        .setRespondWithErrors(true)\n        .setResolver(resolver),\n    ).toThrow('twice');\n  });\n\n  it('should CANNOT build without set resolver', () => {\n    expect(() => ServerlessAdapter.new(null).build()).toThrow('set a resolver');\n  });\n\n  it('should CANNOT build without set framework', () => {\n    expect(() =>\n      ServerlessAdapter.new(null).setResolver(new PromiseResolver()).build(),\n    ).toThrow('set a framework');\n  });\n\n  it('should CANNOT build without set handler', () => {\n    expect(() =>\n      ServerlessAdapter.new(null)\n        .setResolver(new PromiseResolver())\n        .setFramework(new FrameworkMock(200, {}))\n        .build(),\n    ).toThrow('set a handler');\n  });\n\n  it('should CANNOT build without set at least one adapter', () => {\n    expect(() =>\n      ServerlessAdapter.new(null)\n        .setResolver(new PromiseResolver())\n        .setFramework(new FrameworkMock(200, {}))\n        .setHandler(new DefaultHandler())\n        .build(),\n    ).toThrow('one adapter');\n  });\n});\n"
  },
  {
    "path": "tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*.ts\"]\n}\n"
  },
  {
    "path": "tsconfig.doc.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"emitDeclarationOnly\": true,\n    \"noEmit\": false,\n    \"skipDefaultLibCheck\": true,\n    \"skipLibCheck\": true\n  },\n  \"include\": [\"src/**/*.ts\", \"src/index.doc.ts\"],\n  \"exclude\": []\n}\n"
  },
  {
    "path": "tsconfig.eslint.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"noEmit\": true,\n    \"types\": [\n      \"vitest/globals\"\n    ],\n    \"lib\": [\n      \"esnext\"\n    ],\n    \"allowJs\": true,\n    \"checkJs\": true\n  },\n  \"include\": [\n    \"src/**/*.ts\",\n    \"test/**/*.ts\",\n    \"scripts/**/*.ts\",\n    \"vite.config.ts\",\n    \"tsup.config.ts\"\n  ],\n  \"exclude\": [\n    \"benchmark/**/*.ts\"\n  ]\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/tsconfig\",\n  \"compilerOptions\": {\n    \"outDir\": \"./lib\",\n    \"target\": \"ES2022\",\n    \"module\": \"ES2022\",\n    \"moduleResolution\": \"Bundler\",\n    \"incremental\": false,\n    \"noEmit\": true,\n    \"noImplicitAny\": false,\n    \"verbatimModuleSyntax\": true,\n    \"allowUnreachableCode\": false,\n    \"allowUnusedLabels\": false,\n    \"exactOptionalPropertyTypes\": false,\n    \"noImplicitOverride\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"alwaysStrict\": true,\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"esModuleInterop\": true,\n    \"importHelpers\": false,\n    \"newLine\": \"lf\",\n    \"noEmitHelpers\": false,\n    \"noFallthroughCasesInSwitch\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"preserveConstEnums\": true,\n    \"pretty\": true,\n    \"removeComments\": false,\n    \"resolveJsonModule\": true,\n    \"sourceMap\": true,\n    \"strict\": true,\n    \"useDefineForClassFields\": true\n  },\n  \"reflection\": true,\n  \"include\": [\n    \"src/**/*.ts\",\n    \"test/**/*.ts\",\n    \"scripts/**/*.ts\"\n  ],\n  \"exclude\": [\n    \"src/index.doc.ts\",\n    \"benchmark/**/*.ts\"\n  ]\n}\n"
  },
  {
    "path": "tsdoc.json",
    "content": "{\r\n  \"$schema\": \"https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json\",\r\n  \"tagDefinitions\": [\r\n    {\r\n      \"tagName\": \"@breadcrumb\",\r\n      \"syntaxKind\": \"block\",\r\n      \"allowMultiple\": false\r\n    }\r\n  ],\r\n  \"noStandardTags\": false\r\n}\r\n"
  },
  {
    "path": "tsup.config.ts",
    "content": "import { execSync } from 'node:child_process';\nimport { defineConfig } from 'tsup';\n\nconst adapters = [\n  'apollo-server',\n  'aws',\n  'azure',\n  'digital-ocean',\n  'dummy',\n  'huawei',\n];\n\nconst frameworks = [\n  'apollo-server',\n  'body-parser',\n  'cors',\n  'deepkit',\n  'express',\n  'fastify',\n  'hapi',\n  'koa',\n  'lazy',\n  'polka',\n  'trpc',\n];\n\nconst handlers = [\n  'aws',\n  'azure',\n  'default',\n  'digital-ocean',\n  'firebase',\n  'gcp',\n  'huawei',\n];\n\nconst resolvers = ['aws-context', 'callback', 'dummy', 'promise'];\n\nconst libEntries = [\n  ...adapters.map(adapter => `src/adapters/${adapter}/index.ts`),\n  ...frameworks.map(framework => `src/frameworks/${framework}/index.ts`),\n  ...handlers.map(handler => `src/handlers/${handler}/index.ts`),\n  ...resolvers.map(resolver => `src/resolvers/${resolver}/index.ts`),\n];\n\nconst createExport = (filePath: string) => ({\n  import: {\n    types: `./lib/${filePath}.d.ts`,\n    default: `./lib/${filePath}.mjs`,\n  },\n  require: {\n    types: `./lib/${filePath}.d.cts`,\n    default: `./lib/${filePath}.cjs`,\n  },\n});\n\nconst createExportReducer =\n  (initialPath: string) => (acc: object, name: string) => {\n    acc[`./${initialPath}/${name}`] = createExport(\n      `${initialPath}/${name}/index`,\n    );\n\n    acc[`./lib/${initialPath}/${name}`] = createExport(\n      `${initialPath}/${name}/index`,\n    );\n\n    return acc;\n  };\n\nconst packageExports = {\n  '.': createExport('index'),\n  ...adapters.reduce(createExportReducer('adapters'), {}),\n  ...frameworks.reduce(createExportReducer('frameworks'), {}),\n  ...handlers.reduce(createExportReducer('handlers'), {}),\n  ...resolvers.reduce(createExportReducer('resolvers'), {}),\n};\n\nexecSync(`npm pkg set exports='${JSON.stringify(packageExports)}' --json`);\n\nexport default defineConfig({\n  outDir: './lib',\n  clean: true,\n  dts: true,\n  format: ['esm', 'cjs'],\n  outExtension: ({ format }) => ({\n    js: format === 'cjs' ? '.cjs' : '.mjs',\n  }),\n  cjsInterop: true,\n  entry: ['src/index.ts', ...libEntries],\n  sourcemap: true,\n  skipNodeModulesBundle: true,\n  minify: true,\n  target: 'es2022',\n  tsconfig: './tsconfig.build.json',\n  keepNames: true,\n  bundle: true,\n});\n"
  },
  {
    "path": "vite.config.ts",
    "content": "// eslint-disable-next-line import/no-unresolved\nimport { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n  esbuild: {\n    target: 'es2022',\n  },\n  test: {\n    coverage: {\n      provider: 'v8',\n      include: ['src/**'],\n      exclude: [\n        'src/**/@types/**/*.ts',\n        'src/**/index.doc.ts',\n        'src/**/index.ts',\n      ],\n    },\n  },\n});\n"
  },
  {
    "path": "www/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\nsidebar-api-generated.js\n"
  },
  {
    "path": "www/.tool-versions",
    "content": "nodejs 18.18.1\n"
  },
  {
    "path": "www/README.md",
    "content": "# Documentation\n\nThis website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator to create documentation to this library.\n\nSee the website [here](https://viniciusl.com.br/serverless-adapter).\n"
  },
  {
    "path": "www/babel.config.js",
    "content": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "www/blog/2022-06-17-the-beginning.mdx",
    "content": "---\nslug: the-beginning\ntitle: The Beginning\nauthors: [h4ad]\ntags: [serverless-adapter]\n---\n\nHello, welcome to my new library to help you integrate your API with the serverless world.\n\n## The development\n\nIt took me almost 5 months to build this library, refactoring was easy and testing was challenging, but documenting this library was the hardest part.\n\nIt took me almost 2 weeks to refactor [@vendia/serverless-express](https://github.com/vendia/serverless-express),\nabout 1 and a half month to create tests with 99% coverage and the rest of the time I spent creating documentation for this library.\n\nI currently added support for:\n\n- AWS\n  - [AWS Load Balancer](https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html) by using ([AlbAdapter](/docs/main/adapters/aws/alb))\n  - [AWS Api Gateway V1](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html) by using ([ApiGatewayV1Adapter](/docs/main/adapters/aws/api-gateway-v1))\n  - [AWS Api Gateway V2](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html) by using ([ApiGatewayV2Adapter](/docs/main/adapters/aws/api-gateway-v2))\n  - [AWS DynamoDB](https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html) by using ([DynamoDBAdapter](/docs/main/adapters/aws/dynamodb))\n  - [AWS Event Bridge / CloudWatch Events](https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents.html) by using ([EventBridgeAdapter](/docs/main/adapters/aws/event-bridge))\n  - [AWS Lambda Edge](https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html) by using ([LambdaEdgeAdapter](/docs/main/adapters/aws/lambda-edge))\n  - [AWS SNS](https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html) by using ([SNSAdapter](/docs/main/adapters/aws/sns))\n  - [AWS SQS](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html) by using ([SQSAdapter](/docs/main/adapters/aws/sqs))\n- Huawei\n  - [Http Function](https://support.huaweicloud.com/intl/en-us/usermanual-functiongraph/functiongraph_01_1442.html): Look [this section](/docs/main/handlers/huawei#http-function).\n  - [Event Function](https://support.huaweicloud.com/intl/en-us/usermanual-functiongraph/functiongraph_01_1441.html): Look [this section](/docs/main/handlers/huawei#event-function).\n    - [Api Gateway](https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0102.html#functiongraph_02_0102__li5178638110137) by using ([HuaweiApiGatewayAdapter](/docs/main/adapters/huawei/huawei-api-gateway)).\n\nBut it's just the beginning, I'm going to build more adapters to integrate with as much of the cloud as possible, just to be able to deploy my APIs on any cloud.\n\n## About me\n\nI am a student at [Facens](https://facens.br/) university and I work for [Liga](https://liga.facens.br/), which is a sector within Facens that develops applications, websites, games and much more fun stuff.\n\nI currently work on this library only in my spare time and I need to balance my Final Theses and my overtime projects so it was very challenging but I am happy with the end result of this library.\n\n## Inspiration\n\nThis library was originally created to help my company reduce costs with AWS SQS, but it has since turned into something I can spend my time developing and learning English because I'm not a native speaker (as typing problems might suggest) writing all the documentation in English.\n## Credits\n\nI need to thank [@vendia](https://vendia.net/) for developing [@vendia/serverless-express](https://github.com/vendia/serverless-express), all logic and code I finished to refactor from the code I read on serverless-express.\nI also have many thanks to [Chaguri](https://github.com/guichaguri), [Liga](https://liga.facens.br/) and many other people who gave me time and insights to create this library.\n\n## You can use it right now!\n\nSee the [Introduction](/docs/main/intro) section to know more about the library.\n"
  },
  {
    "path": "www/blog/2022-07-17-updates-and-releases.mdx",
    "content": "---\nslug: updates-and-releases\ntitle: Updates and Releases\nauthors: [h4ad]\ntags: [serverless-adapter, trpc, azure, firebase]\nimage: https://images.unsplash.com/photo-1636819488524-1f019c4e1c44\n---\n\nimport BrowserWindow from '@site/src/components/BrowserWindow';\n\n![To the moon!](https://images.unsplash.com/photo-1636819488524-1f019c4e1c44)\n\nNow we have more Handlers, Frameworks and Adapters, let's see what's new.\n\n> From [v2.3.2](https://github.com/H4ad/serverless-adapter/tree/v2.3.2) to [v2.6.0](https://github.com/H4ad/serverless-adapter/tree/v2.6.0),\ncompare the changes [here](https://github.com/H4ad/serverless-adapter/compare/v2.3.2...v2.6.0).\n\n## Changes\n\n42 commits, 6905 lines added, 601 lines deleted, that's the size of the changes since [The Beginning](/blog/the-beginning).\n\nI'm very proud of how things are going, I learned a lot by studying to implement these new things.\n\nBut, let's learn what's new in all these releases.\n\n## Azure and Firebase\n\nYou can now use this library to deploy your apps to [Azure Functions](https://docs.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-node)\nand [Firebase Functions](https://firebase.google.com/docs/functions/http-events).\n\nMore specifically, you can integrate with Http Trigger V4 on Azure and Http Events on Firebase.\n\nThese integrations are just to open the door of possibilities, in the future I want to add support for more triggers in these clouds.\n\nCheck out the [Azure](/docs/main/handlers/azure) and [Firebase](/docs/main/handlers/firebase) docs for how to integrate.\n\nI also added examples for the cloud in the [serverless-adapter-examples](https://github.com/H4ad/serverless-adapter-examples) repository.\n\n## tRPC\n\n<BrowserWindow url=\"https://trpc.io/docs/\">\n  tRPC allows you to easily build & consume fully typesafe APIs, without schemas or code generation.\n</BrowserWindow>\n\ntRPC is a framework that brings a new way of thinking about APIs, instead of REST or GraphQL, you can build typesafe APIs and easily\ncan integrate with the client, seems to be very promising.\n\nSo now you can deploy applications developed with tRPC to any cloud that this library supports, have a look at [docs](/docs/main/frameworks/trpc)\nto learn more about how to use it.\n\n## That's all folks!\n\nI have two more weeks to work in this library without worrying because I'm on vacation at the university,\nso probably my next efforts will be to bring more articles to this blog to show the full power of this library.\n\nGiving some spoilers for those of you that make it this far, I'll start by showing you the benefits of using AWS Lambda integrated with\nAPI Gateway and SQS, I used it in a project of my company and I managed to reduce a lot of stress on the database and now\nwe are able to process 500k votes in minutes without spending 15% CPU using a PostgreSQL database on a t2.micro instance.\n\nThat's all for today, thank you!\n"
  },
  {
    "path": "www/blog/2023-04-28-aws-lambda-response-streaming.mdx",
    "content": "---\nslug: aws-lambda-response-streaming\ntitle: AWS Lambda Response Streaming\nauthors: [h4ad]\ntags: [serverless-adapter, aws, aws-lambda, function-url]\nimage: https://images.unsplash.com/photo-1527489377706-5bf97e608852\n---\n\n![A beautiful stream!](https://images.unsplash.com/photo-1527489377706-5bf97e608852)\n> Image by [Hendrik Cornelissen](https://unsplash.com/@the_bracketeer) on [Unsplash](https://unsplash.com)\n\nIt's been a long time since I wrote a post here, but I'm happy to share this new announcement.\n\n## First, are you new to this library?\n\n![First time?](first-time-meme-first-time.gif)\n\nLet me introduce the library first, I named [Serverless Adapter](/docs/main/intro) because my goal is connect any serverless environment to any NodeJS framework.\n\nSo you could just plug your [framework](/docs/main/architecture#framework), use the correct [handler](/docs/main/architecture#handler) for your serverless environment,\nchoose the [adapters](/docs/main/architecture#adapter) and then you can deploy your application!\n\n### What does this library support?\n\nCurrently, we support [8 NodeJS frameworks](/docs/category/frameworks): [Express](/docs/main/frameworks/express), [Fastify](/docs/main/frameworks/fastify), [tRPC](/docs/main/frameworks/trpc), [Apollo Server](/docs/main/frameworks/apollo-server), [NestJS](/docs/main/frameworks/nestjs), [Deepkit](/docs/main/frameworks/deepkit), [Koa](/docs/main/frameworks/koa) and [Hapi](/docs/main/frameworks/Hapi).\n\nWe also support [6 serverless environments](/docs/category/handlers): [AWS](/docs/main/handlers/aws), [Azure](/docs/main/handlers/azure), [Google Cloud](/docs/main/handlers/gcp), [Digital Ocean](/docs/main/handlers/digital-ocean), [Firebase](/docs/main/handlers/firebase) and [Huawei](/docs/main/handlers/huawei).\n\nTalking about AWS, we support [10 different services](/docs/category/aws) like API Gateway [V1](/docs/main/adapters/aws/api-gateway-v1) and [V2](/docs/main/adapters/aws/api-gateway-v2), [SQS](/docs/main/adapters/aws/sqs), [SNS](/docs/main/adapters/aws/sns), etc... and you can combine them to use the same codebase and lambda to handle them all.\n\n:::tip\nTo learn understand the power of this composability, check this article I wrote about how I went [From a million invocations to a thousand with correct caching](https://viniciusl.com.br/posts/2022/12/08-from-million-invocations-to-thousand-with-correct-caching/).\n:::\n\nBut okay, enough self-marketing, let's get to the main point of this article.\n\n## AWS Lambda Response Streaming\n\nToday I'm rolling out support for [AWS Lambda Streaming Response](https://aws.amazon.com/blogs/compute/introducing-aws-lambda-response-streaming/) using [AwsStreamHandler](/docs/main/handlers/aws#aws-lambda-response-streaming).\n\nIf you already use this library, just change [DefaultHandler](/docs/main/handlers/aws#usage) to [AwsStreamHandler](/docs/main/handlers/aws#aws-lambda-response-streaming), and make sure you're using [DummyResolver](/docs/api/Resolvers/DummyResolver) and [ApiGatewayV2Adapter](/docs/main/adapters/aws/api-gateway-v2):\n\n```ts title=\"index.ts\"\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\nimport { AwsStreamHandler } from '@h4ad/serverless-adapter/handlers/aws';\nimport { DummyResolver } from '@h4ad/serverless-adapter/resolvers/dummy';\nimport { ApiGatewayV2Adapter } from '@h4ad/serverless-adapter/adapters/aws';\nimport app from './app';\n\nexport const handler = ServerlessAdapter.new(app)\n// .setHandler(new DefaultHandler())\n   .setHandler(new AwsStreamHandler())\n   .setResolver(new DummyResolver())\n   .setAdapter(new ApiGatewayV2Adapter())\n   // more options...\n   //.setFramework(new ExpressFramework())\n   .build();\n```\n\n> Despite its name, `ApiGatewayV2Adapter` can be used to support API Gateway V2 and function URLs.\n\n:::caution\nResponse streaming currently is only available for Function URLs.\n:::\n\nThat's it :) Now you can use Function URLs and stream your content to the world!\n\n:::information\nDon't forget to enable the feature in your AWS Lambda function by changing `BUFFERED` TO `RESPONSE_STREAM.`\n:::\n\n### I NEED CODE!!!\n\nWell, if you're the type of person who, like me, needs to see the code working, here's a repository with several example projects using this library:\n[serverless-adapter-examples](https://github.com/H4ad/serverless-adapter-examples).\n\n## Beyond HTTP Requests\n\nFurthermore, not only can you receive HTTP requests using `Function URLs`, but you can combine your `SQS` queue and use the same codebase to process everything.\n\nI haven't spent a lot of time testing it, but so far, any AWS service that supports this library can be hooked up to your Lambda function with `RESPONSE_STREAM` enabled.\n\nThe only thing you need to know is: the answer didn't work as expected, I couldn't get the [SQS Partial Response](/docs/main/adapters/aws/sqs#batch-item-failures) to work for example .\n\nBut you can give it a try anyway, share your results with me on [twitter](https://twitter.com/vinii_joga10) and I'll be happy to help if I can.\n\n## Conclusion\n\nWell, I don't have much to say, but I hope you enjoy this new feature and use it to build amazing things.\n\nI've spent the last 3 weeks trying to figure out how to make this work and I'm happy with the result.\n\nIf you're curious enough to learn more about how I implement it, you can see [this PR](https://github.com/H4ad/serverless-adapter/pull/90) with all my struggles and thoughts over the weeks.\n"
  },
  {
    "path": "www/blog/2023-12-25-dual-package-publish.mdx",
    "content": "---\nslug: dual-package-publish\ntitle: Support for Dual Package Publish\nauthors: [h4ad]\ntags: [serverless-adapter, cjs, esm, npm, package, publish]\nimage: https://images.unsplash.com/photo-1429743305873-d4065c15f93e\n---\n\n\n\n\n\n\n\n\n\n\n\nimport BrowserWindow from '@site/src/components/BrowserWindow';\n\n![Two paths inside a forest!](https://images.unsplash.com/photo-1429743305873-d4065c15f93e)\n> Image by [Jens Lelie](https://unsplash.com/@madebyjens) on [Unsplash](https://unsplash.com)\n\nThis feature was initially asked by [ClementCornut](https://github.com/ClementCornut) on issue [#127](https://github.com/H4ad/serverless-adapter/issues/127).\n\nInitially I was a little unsure whether to publish `esm` and `cjs`, but then I started to like the idea of exporting\nmy packages as `@h4ad/serverless-adapter/adapters/aws`.\n\nYou can use it by installing the new version:\n\n```bash\nnpm i @h4ad/serverless-adapter@4.0.1\n```\n\n> The version 4.0.0 was released with a bug that didn't include the package files, so I released the version 4.0.1 to fix this issue.\n\nIn the previous version, since I only export to `commonjs`, you need to import the files as `/lib/adapters/aws`, which is not bad, but not exactly good.\nThis was necessary because I can't export all files in the default `export` as this will lead you to install all frameworks supported by this library.\n\nBut ok, I had some problems while adding support for dual-package publishing which I want to share with you only,\nand especially for my future version if you want to add support for dual-package publishing in your modules.\n\n## Vite\n\nI already use `vitest` test my package and to build the previous versions,\nit works great and is specially fast to run the tests (5.82s to run 456 tests across 52 files).\n\nBut the configuration to build was a little bit nightmare:\n\n```ts title=\"vite.config.ts\"\n// some initial configuration lines...\n  ...(!isTest && {\n    esbuild: {\n      format: 'cjs',\n      platform: 'node',\n      target: 'node18',\n      sourcemap: 'external',\n      minifyIdentifiers: false,\n    },\n    build: {\n      outDir: 'lib',\n      emptyOutDir: true,\n      sourcemap: true,\n      lib: {\n        entry: path.resolve(__dirname, 'src/index.ts'),\n        formats: ['cjs'],\n      },\n      rollupOptions: {\n        external: ['yeoman-generator'],\n        input: glob.sync(path.resolve(__dirname, 'src/**/*.ts')),\n        output: {\n          preserveModules: true,\n          entryFileNames: entry => {\n            const { name } = entry;\n\n            const fileName = `${name}.js`;\n\n            return fileName;\n          },\n        },\n      },\n    },\n  }),\n```\n\nAll of this configuration was necessary as I need to build my package to match exactly the same structure as `src`,\nwhich was needed for users to import as `/lib/adapters/aws`.\n\nOn the first attempt, I just tried to extend this configuration, but I spent a few hours and managed to generate\na good package output, but it was missing some details that were very painful to bear, such as correctly emitting `d.cts`.\n\nIf you want to see how it turned out, if you want to try doing this using `vite` directly,\n[here is vite.config.ts](https://github.com/H4ad/serverless-adapter/blob/f642739334687b0a22312074a6e225e9f8ac8124/vite.config.ts).\n\nBut then I started to give up and [tweeted about it](https://twitter.com/vinii_joga10/status/1738954683853451760).\n\n## Suggestions from Twitter\n\nI got some incredible helpful messages on twitter and I will cover those suggestions that I applied to be able to finally support dual package publish.\n\n### Re-exporting on mjs\n\nThis was a suggestion from [Matteo Collina](https://twitter.com/matteocollina), he also sent me the package [snap](https://github.com/mcollina/snap) which does this re-export,\nwhich I also saw being used in [Orama](https://github.com/oramasearch/orama/blob/main/packages/orama/src/cjs/index.cts), is basically doing this:\n\n<BrowserWindow url=\"https://nodejs.org/api/packages.html#approach-2-isolate-state\">\n  Your state:\n\n  ```js title=\"./node_modules/pkg/state.cjs\"\n  import Date from 'date';\n  const someDate = new Date();\n  ```\n\n  Define/export on `cjs`.\n\n  ```js title=\"./node_modules/pkg/index.cjs\"\n  const state = require('./state.cjs');\n  module.exports.state = state;\n  ```\n\n  Re-export on `mjs`.\n\n  ```js title=\"./node_modules/pkg/index.mjs\"\n  import state from './state.cjs';\n  export {\n  state,\n};\n  ```\n</BrowserWindow>\n\nThis way, I solve the problem of state isolation, but I will need:\n\n- or manually export all these files\n- or use a tool to automate this process\n\nBoth ways will be a bit painful to maintain, so I didn't go that route.\n\nThis approach can be fine if your library maintains state and the codebase is pure javascript.\n\n### tsup\n\nInstead of trying to go through this configuration hell in `vite`, [Michele Riva](https://twitter.com/MicheleRivaCode)\nsuggested [tsup](https://tsup.egoist.dev/) which is incredibly easy to use.\n\nI spent less than 10 minutes to generate almost the same output as the previous configuration with `vite`,\nbut this time the output was correct, with `d.cts` files being generated.\n\nMy configuration file now looks like this:\n\n```ts title=\"tsup.config.ts\"\nexport default defineConfig({\n  outDir: './lib',\n  clean: true,\n  dts: true,\n  format: ['esm', 'cjs'],\n  outExtension: ({ format }) => ({\n    js: format === 'cjs' ? '.cjs' : '.mjs',\n  }),\n  cjsInterop: true,\n  // the libEntries is basically all the entries I need to export,\n  // like: adapters/aws, frameworks/fastify, etc...\n  entry: ['src/index.ts', ...libEntries],\n  sourcemap: true,\n  skipNodeModulesBundle: true,\n  minify: true,\n  target: 'es2022',\n  tsconfig: './tsconfig.build.json',\n  keepNames: true,\n  bundle: true,\n});\n```\n\n### package.json exports\n\nSince I have a lot of things to export, I also automate the configuration of `exports` in `package.json` with:\n\n```ts title=\"tsup.config.ts\"\n// I do the same for adapters, frameworks and handlers\nconst resolvers = ['aws-context', 'callback', 'dummy', 'promise'];\n\nconst libEntries = [\n  ...resolvers.map(resolver => `src/resolvers/${resolver}/index.ts`),\n];\n\nconst createExport = (filePath: string) => ({\n  import: {\n    types: `./lib/${filePath}.d.ts`,\n    default: `./lib/${filePath}.mjs`,\n  },\n  require: {\n    types: `./lib/${filePath}.d.cts`,\n    default: `./lib/${filePath}.cjs`,\n  },\n});\n\nconst createExportReducer =\n  (initialPath: string) => (acc: object, name: string) => {\n    acc[`./${initialPath}/${name}`] = createExport(\n      `${initialPath}/${name}/index`,\n    );\n\n    acc[`./lib/${initialPath}/${name}`] = createExport(\n      `${initialPath}/${name}/index`,\n    );\n\n    return acc;\n  };\n\nconst packageExports = {\n  '.': createExport('index'),\n  ...resolvers.reduce(createExportReducer('resolvers'), {}),\n  // and I also do the same for adapters, frameworks and handlers.\n};\n\n// this command does the magic to update my package.json\nexecSync(`npm pkg set exports='${JSON.stringify(packageExports)}' --json`);\n```\n\nThis works incredible and also keep my `package.json` updated.\n\n### Module not found on moduleResolution `node`\n\nBut there is one thing you should pay attention to, did you see that I export files with the prefix `./lib`?\n\n```json title=\"package.json\"\n  \"exports\": {\n    \"./adapters/apollo-server\": {...},\n    \"./lib/adapters/apollo-server\": {...},\n  }\n```\n\nThe content of both is the same, but I do this to be compatible with the resolution of `node`.\nWithout this configuration, the `IDE` will show the import to `@h4ad/serverless-adapter/adapters/apollo-server` as resolved, but\n`node` will not be able to find the file during the runtime.\n\nAnd the interesting part of doing this is that people who import this package with `/lib` will still be able to import the code,\nand they won't need any code modifications.\n\nMaybe I could release this feature without it being a breaking change with this change, but to be on the safe side,\nI released it as a breaking change anyway.\n\n### publint\n\nThe [publint](https://publint.dev/) is a tool that I learned on [ESM Modernization Lessons](https://blog.isquaredsoftware.com/2023/08/esm-modernization-lessons/#early-attempts) inside `Early Attempts`,\nthis article was a suggestion by [Luca Micieli](https://twitter.com/LucaRams23).\n\nWith this tool, I detect several problems with the `exports` configuration and this will make your life a lot easier.\n\nBut this tool has a problem that they didn't catch, and this problem was pointed out by [Michele Riva](https://twitter.com/MicheleRivaCode), instead:\n\n```json title=\"package.json\"\n\"exports\": {\n  \"resolvers/promise\": {\n```\n\nI should export it with the prefix `./`:\n\n```json title=\"package.json\"\n\"exports\": {\n  \"./resolvers/promise\": {\n```\n\nThis small detail can make your configuration fail.\n\n### verdaccio\n\nThe [verdaccio](https://verdaccio.org/) was suggested by [Abhijeet Prasad](https://twitter.com/imabhiprasad), with this tool you can have your private registry that you can use to test,\nAbhijeet use this tool on [Sentry](https://sentry.io/) SDKs to do e2e tests.\n\nWith this tool, I was able to make sure the package was working correctly with the new dual package publish.\n\n### Wrong `moduleResolution`\n\nIt took me a while to realize, but while testing the changes in a sample project, the imports still failed because TypeScript couldn't find the files.\n\nSo I remember the suggestion from [sami](https://twitter.com/samijaber_) who gave me some examples of projects he uses\nin [BuilderIO/hidration-overlay](https://github.com/BuilderIO/hydration-overlay/tree/main/tests),\nand I understand the difference between `moduleResolution`, in my project it was configured for `node`,\nin his project it was configured for `bundler`.\n\nWhen I changed this setting, all imports started working and imports using `/lib/adapters/aws` started failing.\n\nIf you're like me and have no idea what this setting is about, the documentation says:\n\n<BrowserWindow url=\"https://www.typescriptlang.org/tsconfig#moduleResolution\">\n  Specify the module resolution strategy:\n\n  'node16' or 'nodenext' for modern versions of Node.js. Node.js v12 and later supports both ECMAScript imports and\n  CommonJS require, which resolve using different algorithms. These moduleResolution values, when combined with the\n  corresponding module values, picks the right algorithm for each resolution based on whether Node.js will see an import\n  or require in the output JavaScript code.\n\n  'node10' (previously called 'node') for Node.js versions older than v10, which only support CommonJS require. You\n  probably won’t need to use node10 in modern code.\n\n  'bundler' for use with bundlers. Like node16 and nodenext, this mode supports package.json \"imports\" and \"exports\",\n  but unlike the Node.js resolution modes, bundler never requires file extensions on relative paths in imports.\n</BrowserWindow>\n\nMake sense why it was not working at all, `node` was not built to support `exports`, and only `nodenext` and `bundler` should work correctly.\n\n## Doubling the package size\n\nSomething I saw that made me a little worried was the size of this package, since I need to export the code, types and source maps twice, the package\nwent from `~600Kb` to `~1.5Mb`.\n\nI enabled minification to try to reduce the amount of code shipped, but if you use this library and don't have any kind of minification/bundling\nduring your build, I highly recommend you look into these libraries to help you with the size of your zip file being uploaded:\n\n- [@h4ad/node-modules-packer](https://github.com/H4ad/node-modules-packer)\n- [ncc](https://github.com/vercel/ncc)\n- [zip-it-and-ship-it](https://github.com/netlify/zip-it-and-ship-it)\n\n## Conclusions\n\nThe `esm` packages was a nightmare to support some time ago but the ecosystem is starting solving problems with new tools to bundle your project\ninstead of having to fight with your own configuration files.\n\nThe `cjs` is a no-brain solution, almost no configuration and it works great but maybe is not ideal for your consumers/clients, some of them can have issues\nlike [ClementCornut](https://github.com/ClementCornut) that needed to import the files with the full path `import awsPkg from \"@h4ad/serverless-adapter/lib/adapters/aws/index.js\";`.\n\nWhen I started adding this feature, I had no knowledge of how to publish double packages, I basically go-horse in the early hours\nof my implementation and then I started learning more about how it works and how to properly configure the package.\n\nThis makes me realize that dual-package publishing isn't the nightmare I initially thought, I just didn't learn from the\nprevious mistakes other people made and I should have read more articles about it before I started implementing it.\n\nMy sincere thanks to:\n\n- [Abhijeet Prasad](https://twitter.com/imabhiprasad)\n- [Luca Micieli](https://twitter.com/LucaRams23)\n- [Matteo Collina](https://twitter.com/matteocollina)\n- [Michele Riva](https://twitter.com/MicheleRivaCode)\n- [sami](https://twitter.com/samijaber_)\n\nWithout you, it will probably take me a lot longer to be able to convince myself to go ahead and try again to add support\nfor dual-package publish after the first failures.\n"
  },
  {
    "path": "www/blog/authors.yml",
    "content": "h4ad:\n  name: Vinícius Lourenço\n  title: Maintainer of Serverless Adapter\n  url: https://github.com/h4ad\n  image_url: https://github.com/h4ad.png\n"
  },
  {
    "path": "www/docs/.gitignore",
    "content": "/api/*\r\n"
  },
  {
    "path": "www/docs/main/adapters/aws/alb.mdx",
    "content": "---\r\ntitle: ALB\r\ndescription: See more about how to integrate with AWS Application Load Balancer.\r\n---\r\n\r\nThe adapter to handle requests from [AWS Application Load Balancer](https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html).\r\n\r\n:::info\r\n\r\nWhen an error is thrown during forwarding and the `responseWithErrors` option is `true`, we return a 500 status WITH error stack in the response.\r\n\r\n:::\r\n\r\n:::tip Reducing Costs\r\n\r\nNot sure when to use AWS ALB instead of API Gateway? See [this article](https://serverless-training.com/articles/save-money-by-replaceing-api-gateway-with-application-load-balancer/) from Serverless Training to learn more.\r\n\r\n:::\r\n\r\n## About the adapter\r\n\r\nThis adapter turns every request coming from AWS ALB into an HTTP request to your framework.\r\n\r\n```json title=\"alb-event-example.json\"\r\n{\r\n    \"requestContext\": {\r\n        \"elb\": {\r\n            \"targetGroupArn\": \"arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/lambda-279XGJDqGZ5rsrHC2Fjr/49e9d65c45c6791a\"\r\n        }\r\n    },\r\n    \"httpMethod\": \"POST\",\r\n    \"path\": \"/lambda\",\r\n    \"queryStringParameters\": {\r\n        \"query\": \"1234ABCD\"\r\n    },\r\n    \"headers\": {\r\n        \"accept\": \"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\",\r\n        \"accept-encoding\": \"gzip\",\r\n        \"accept-language\": \"en-US,en;q=0.9\",\r\n        \"connection\": \"keep-alive\",\r\n        \"host\": \"lambda-alb-123578498.us-east-2.elb.amazonaws.com\",\r\n        \"upgrade-insecure-requests\": \"1\",\r\n        \"user-agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36\",\r\n        \"x-amzn-trace-id\": \"Root=1-5c536348-3d683b8b04734faae651f476\",\r\n        \"x-forwarded-for\": \"72.12.164.125\",\r\n        \"x-forwarded-port\": \"80\",\r\n        \"x-forwarded-proto\": \"http\",\r\n        \"x-imforwards\": \"20\"\r\n    },\r\n    \"body\": \"Banana\",\r\n    \"isBase64Encoded\": false\r\n}\r\n```\r\n\r\nSo, to add support to the above request, we must have registered the `/lambda` route as `POST` and when API Gateway sends this event, you will get:\r\n\r\n- `body`: `Banana`\r\n- `queryString`: `query=1234ABCD`\r\n\r\n## Customizing\r\n\r\nYou can remove some base path with the `stripBasePath` option inside [AlbAdapterOptions](/docs/api/Adapters/AWS/AlbAdapter/AlbAdapterOptions).\r\n\r\n:::caution\r\n\r\nWhen you configure your API with some `basePath` like `/prod`, you should either send the request in the path `/prod/lambda` or set `stripBasePath` to `/prod`.\r\n\r\n:::\r\n\r\n## Usage\r\n\r\nTo add support to AWS ALB you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { AlbAdapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new DefaultHandler())\r\n  // .setFramework(new ExpressFramework())\r\n  // .setResolver(new PromiseResolver())\r\n  .addAdapter(new AlbAdapter())\r\n  // customizing:\r\n  // .addAdapter(new AlbAdapter({ stripBasePath: '/prod' }))\r\n  .build();\r\n```\r\n\r\n### Transfer Encoding Chunked\r\n\r\nALB currently didn't support chunked transfer, so the response body will be buffered\r\nwithout the special characters introduced by the chunked transfer keeping the body complete.\r\n"
  },
  {
    "path": "www/docs/main/adapters/aws/api-gateway-v1.mdx",
    "content": "---\r\ntitle: Api Gateway V1\r\ndescription: See more about how to integrate with AWS API Gateway V1.\r\n---\r\n\r\nThe adapter to handle requests from [AWS Api Gateway V1](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html).\r\n\r\n:::info\r\n\r\nWhen an error is thrown during forwarding and the `responseWithErrors` option is `true`, we return a 500 status WITH error stack in the response.\r\n\r\n:::\r\n\r\n:::tip Reducing Costs\r\n\r\nNot sure when to use AWS ALB instead of API Gateway? See [this article](https://serverless-training.com/articles/save-money-by-replaceing-api-gateway-with-application-load-balancer/) from Serverless Training to learn more.\r\n\r\n:::\r\n\r\n## About the adapter\r\n\r\nThis adapter turns every request coming from API Gateway V1 into an HTTP request to your framework.\r\n\r\n```json title=\"api-gateway-v1-event-example.json\"\r\n{\r\n  \"version\": \"1.0\",\r\n  \"resource\": \"/my/path\",\r\n  \"path\": \"/my/path\",\r\n  \"httpMethod\": \"GET\",\r\n  \"headers\": {\r\n    \"header1\": \"value1\",\r\n    \"header2\": \"value2\"\r\n  },\r\n  \"multiValueHeaders\": {\r\n    \"header1\": [\r\n      \"value1\"\r\n    ],\r\n    \"header2\": [\r\n      \"value1\",\r\n      \"value2\"\r\n    ]\r\n  },\r\n  \"queryStringParameters\": {\r\n    \"parameter1\": \"value1\",\r\n    \"parameter2\": \"value\"\r\n  },\r\n  \"multiValueQueryStringParameters\": {\r\n    \"parameter1\": [\r\n      \"value1\",\r\n      \"value2\"\r\n    ],\r\n    \"parameter2\": [\r\n      \"value\"\r\n    ]\r\n  },\r\n  \"requestContext\": {\r\n    \"accountId\": \"123456789012\",\r\n    \"apiId\": \"id\",\r\n    \"authorizer\": {\r\n      \"claims\": null,\r\n      \"scopes\": null\r\n    },\r\n    \"domainName\": \"id.execute-api.us-east-1.amazonaws.com\",\r\n    \"domainPrefix\": \"id\",\r\n    \"extendedRequestId\": \"request-id\",\r\n    \"httpMethod\": \"GET\",\r\n    \"identity\": {\r\n      \"accessKey\": null,\r\n      \"accountId\": null,\r\n      \"caller\": null,\r\n      \"cognitoAuthenticationProvider\": null,\r\n      \"cognitoAuthenticationType\": null,\r\n      \"cognitoIdentityId\": null,\r\n      \"cognitoIdentityPoolId\": null,\r\n      \"principalOrgId\": null,\r\n      \"sourceIp\": \"IP\",\r\n      \"user\": null,\r\n      \"userAgent\": \"user-agent\",\r\n      \"userArn\": null,\r\n      \"clientCert\": {\r\n        \"clientCertPem\": \"CERT_CONTENT\",\r\n        \"subjectDN\": \"www.example.com\",\r\n        \"issuerDN\": \"Example issuer\",\r\n        \"serialNumber\": \"a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1\",\r\n        \"validity\": {\r\n          \"notBefore\": \"May 28 12:30:02 2019 GMT\",\r\n          \"notAfter\": \"Aug  5 09:36:04 2021 GMT\"\r\n        }\r\n      }\r\n    },\r\n    \"path\": \"/my/path\",\r\n    \"protocol\": \"HTTP/1.1\",\r\n    \"requestId\": \"id=\",\r\n    \"requestTime\": \"04/Mar/2020:19:15:17 +0000\",\r\n    \"requestTimeEpoch\": 1583349317135,\r\n    \"resourceId\": null,\r\n    \"resourcePath\": \"/my/path\",\r\n    \"stage\": \"$default\"\r\n  },\r\n  \"pathParameters\": null,\r\n  \"stageVariables\": null,\r\n  \"body\": \"Hello from Lambda!\",\r\n  \"isBase64Encoded\": false\r\n}\r\n```\r\n\r\nSo, to add support to the above request, we must have registered the `/my/path` route as `POST` and when API Gateway sends this event, you will get:\r\n\r\n- `body`: `Hello from Lambda`\r\n- `queryString`: `parameter1=value1&parameter1=value2&parameter2=value`\r\n\r\n## Customizing\r\n\r\nYou can remove some base path with the `stripBasePath` option inside [ApiGatewayV1Options](/docs/api/Adapters/AWS/ApiGatewayV1Adapter/ApiGatewayV1Options).\r\n\r\n:::caution\r\n\r\nWhen you configure your API with some `basePath` like `/prod`, you should either send the request in the path `/prod/my/path` or set `stripBasePath` to `/prod`.\r\n\r\n:::\r\n\r\nYou can also ensure request headers are lowercase like the default behavior of Node.js `http` module by setting the `lowercaseRequestHeaders` option to `true`.\r\n\r\n:::caution\r\n\r\nApiGateway may already be ensuring your headers are lowercase but it may be worth confirming in your own system as many libraries in the Node.js ecosystem will assume this lowercasing.\r\n\r\n:::\r\n\r\n\r\n## Usage\r\n\r\nTo add support to AWS API Gateway V1 you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { ApiGatewayV1Adapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new DefaultHandler())\r\n  // .setFramework(new ExpressFramework())\r\n  // .setResolver(new PromiseResolver())\r\n  .addAdapter(new ApiGatewayV1Adapter())\r\n  // customizing:\r\n  // .addAdapter(new ApiGatewayV1Adapter({ stripBasePath: '/prod' }))\r\n  .build();\r\n```\r\n\r\n### Transfer Encoding Chunked\r\n\r\nAPI Gateway V1 currently didn't support chunked transfer, so we throw an exception when you send the `transfer-encoding=chunked`.\r\n\r\nBut, you can disable the exception by setting the `throwOnChunkedTransferEncoding` to `false` in the [ApiGatewayV1Options](/docs/api/Adapters/AWS/ApiGatewayV1Adapter/ApiGatewayV1Options).\r\n\r\n```ts title=\"index.ts\"\r\nnew ApiGatewayV1Adapter({ throwOnChunkedTransferEncoding: false })\r\n```\r\n\r\nThe response body will be buffered without the special characters introduced by the chunked transfer keeping the body complete.\r\n"
  },
  {
    "path": "www/docs/main/adapters/aws/api-gateway-v2.mdx",
    "content": "---\r\ntitle: Api Gateway V2\r\ndescription: See more about how to integrate with AWS API Gateway V2.\r\n---\r\n\r\nThe adapter to handle requests from [AWS Api Gateway V2](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html)\r\nand from [AWS Lambda Function URLs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html).\r\n\r\n:::info\r\n\r\nWhen an error is thrown during forwarding and the `responseWithErrors` option is `true`, we return a 500 status WITH error stack in the response.\r\n\r\n:::\r\n\r\n:::tip Reducing Costs\r\n\r\nNot sure when to use AWS ALB instead of API Gateway? See [this article](https://serverless-training.com/articles/save-money-by-replaceing-api-gateway-with-application-load-balancer/) from Serverless Training to learn more.\r\n\r\n:::\r\n\r\n## About the adapter\r\n\r\nThis adapter transforms every request coming from API Gateway V2 into an HTTP request to your framework.\r\n\r\n```json title=\"api-gateway-v2-event-example.json\"\r\n{\r\n  \"version\": \"2.0\",\r\n  \"routeKey\": \"$default\",\r\n  \"rawPath\": \"/my/path\",\r\n  \"rawQueryString\": \"parameter1=value1&parameter1=value2&parameter2=value\",\r\n  \"cookies\": [\r\n    \"cookie1\",\r\n    \"cookie2\"\r\n  ],\r\n  \"headers\": {\r\n    \"header1\": \"value1\",\r\n    \"header2\": \"value1,value2\"\r\n  },\r\n  \"queryStringParameters\": {\r\n    \"parameter1\": \"value1,value2\",\r\n    \"parameter2\": \"value\"\r\n  },\r\n  \"requestContext\": {\r\n    \"accountId\": \"123456789012\",\r\n    \"apiId\": \"api-id\",\r\n    \"authentication\": {\r\n      \"clientCert\": {\r\n        \"clientCertPem\": \"CERT_CONTENT\",\r\n        \"subjectDN\": \"www.example.com\",\r\n        \"issuerDN\": \"Example issuer\",\r\n        \"serialNumber\": \"a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1\",\r\n        \"validity\": {\r\n          \"notBefore\": \"May 28 12:30:02 2019 GMT\",\r\n          \"notAfter\": \"Aug  5 09:36:04 2021 GMT\"\r\n        }\r\n      }\r\n    },\r\n    \"authorizer\": {\r\n      \"jwt\": {\r\n        \"claims\": {\r\n          \"claim1\": \"value1\",\r\n          \"claim2\": \"value2\"\r\n        },\r\n        \"scopes\": [\r\n          \"scope1\",\r\n          \"scope2\"\r\n        ]\r\n      }\r\n    },\r\n    \"domainName\": \"id.execute-api.us-east-1.amazonaws.com\",\r\n    \"domainPrefix\": \"id\",\r\n    \"http\": {\r\n      \"method\": \"POST\",\r\n      \"path\": \"/my/path\",\r\n      \"protocol\": \"HTTP/1.1\",\r\n      \"sourceIp\": \"IP\",\r\n      \"userAgent\": \"agent\"\r\n    },\r\n    \"requestId\": \"id\",\r\n    \"routeKey\": \"$default\",\r\n    \"stage\": \"$default\",\r\n    \"time\": \"12/Mar/2020:19:03:58 +0000\",\r\n    \"timeEpoch\": 1583348638390\r\n  },\r\n  \"body\": \"Hello from Lambda\",\r\n  \"pathParameters\": {\r\n    \"parameter1\": \"value1\"\r\n  },\r\n  \"isBase64Encoded\": false,\r\n  \"stageVariables\": {\r\n    \"stageVariable1\": \"value1\",\r\n    \"stageVariable2\": \"value2\"\r\n  }\r\n}\r\n```\r\n\r\nSo, to add support to the above request, we must have registered the `/my/path` route as `POST` and when API Gateway sends this event, you will get:\r\n\r\n- `body`: `Hello from Lambda`\r\n- `queryString`: `parameter1=value1&parameter1=value2&parameter2=value`\r\n\r\n## Customizing\r\n\r\nYou can strip base path with the option `stripBasePath` inside [ApiGatewayV2Options](/docs/api/Adapters/AWS/ApiGatewayV2Adapter/ApiGatewayV2Options).\r\n\r\n:::caution\r\n\r\nWhen you configure your API with some `basePath` like `/prod`, you should either send the request in the path `/prod/my/path` or set `stripBasePath` to `/prod`.\r\n\r\n:::\r\n\r\n## Usage\r\n\r\nTo add support to AWS API Gateway V2 you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { ApiGatewayV2Adapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new DefaultHandler())\r\n  // .setFramework(new ExpressFramework())\r\n  // .setResolver(new PromiseResolver())\r\n  .addAdapter(new ApiGatewayV2Adapter())\r\n  // customizing:\r\n  // .addAdapter(new ApiGatewayV2Adapter({ stripBasePath: '/prod' }))\r\n  .build();\r\n```\r\n\r\n### Transfer Encoding Chunked\r\n\r\nAPI Gateway V2 currently didn't support chunked transfer, so we throw an exception when you send the `transfer-encoding=chunked`.\r\n\r\nBut, you can disable the exception by setting the `throwOnChunkedTransferEncoding` to `false` in the [ApiGatewayV2Options](/docs/api/Adapters/AWS/ApiGatewayV2Adapter/ApiGatewayV2Options).\r\n\r\n```ts title=\"index.ts\"\r\nnew ApiGatewayV1Adapter({ throwOnChunkedTransferEncoding: false })\r\n```\r\n\r\nThe response body will be buffered without the special characters introduced by the chunked transfer keeping the body complete.\r\n"
  },
  {
    "path": "www/docs/main/adapters/aws/dynamodb.mdx",
    "content": "---\r\ntitle: DynamoDB\r\ndescription: See more about how to integrate with AWS DynamoDB.\r\n---\r\n\r\nThe adapter to handle requests from [AWS DynamoDB](https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html).\r\n\r\n:::info\r\n\r\nThe option of `responseWithErrors` is ignored by this adapter and we always call `resolver.fail` with the error.\r\n\r\n:::\r\n\r\n## Typescript\r\n\r\nTo correctly type your `body` when receiving the AWS DynamoDB request, you must install `aws-lambda`:\r\n\r\n```bash\r\nnpm i --save-dev @types/aws-lambda\r\n```\r\n\r\nSo when getting the `body` you should use this type:\r\n\r\n```ts title=\"dynamodb.controller.ts\"\r\nimport type { DynamoDBStreamEvent } from 'aws-lambda';\r\n```\r\n\r\n## About the adapter\r\n\r\nIn AWS DynamoDB, you don't have requests, you just receive the records in the `event` property of the handler.\r\n\r\nSo, in order to handle this adapter, by default we create a `POST` request to `/dynamo` with the `body` being the `event` property as JSON.\r\n\r\n```json title=\"dynamodb-event-example.json\"\r\n{\r\n  \"Records\": [\r\n    {\r\n      \"eventID\": \"1\",\r\n      \"eventVersion\": \"1.0\",\r\n      \"dynamodb\": {\r\n        \"Keys\": {\r\n          \"Id\": {\r\n            \"N\": \"101\"\r\n          }\r\n        },\r\n        \"NewImage\": {\r\n          \"Message\": {\r\n            \"S\": \"New item!\"\r\n          },\r\n          \"Id\": {\r\n            \"N\": \"101\"\r\n          }\r\n        },\r\n        \"StreamViewType\": \"NEW_AND_OLD_IMAGES\",\r\n        \"SequenceNumber\": \"111\",\r\n        \"SizeBytes\": 26\r\n      },\r\n      \"awsRegion\": \"us-west-2\",\r\n      \"eventName\": \"INSERT\",\r\n      \"eventSourceARN\": \"arn:aws:dynamodb:us-east-1:111122223333:table/EventSourceTable\",\r\n      \"eventSource\": \"aws:dynamodb\"\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\nNormally, your framework will parse this JSON and return the parsed values as javascript objects.\r\n\r\n## Customizing\r\n\r\nYou can change the HTTP Method and Path that will be used to create the request by sending `dynamoDBForwardMethod` and `dynamoDBForwardPath` inside [DynamoDBAdapterOptions](/docs/api/Adapters/AWS/DynamoDBAdapter/DynamoDBAdapterOptions).\r\n\r\n## Usage\r\n\r\nTo add support to AWS DynamoDB you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { DynamoDBAdapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new DefaultHandler())\r\n  // .setFramework(new ExpressFramework())\r\n  // .setResolver(new PromiseResolver())\r\n  .addAdapter(new DynamoDBAdapter())\r\n  // customizing:\r\n  // .addAdapter(new DynamoDBAdapter({ dynamoDBForwardPath: '/prod/dynamo', dynamoDBForwardMethod: 'PUT' }))\r\n  .build();\r\n```\r\n\r\n:::caution\r\n\r\nWhen you configure your API with some `basePath` like `/prod`, you should set `dynamoDBForwardPath` as `/prod/dynamo` instead leave as default `/dynamo`.\r\n\r\n:::\r\n\r\n## Security\r\n\r\nYou **MUST** check if the header `Host` contains the value of `dynamodb.amazonaws.com`.\r\n\r\nWithout checking this header, if you add this adapter and [AWS API Gateway V2](./api-gateway-v2) adapter, you will be vulnerable to attacks\r\nbecause anyone can create a `POST` request to `/dynamo`.\r\n\r\n## What happens when my response status is different from 2xx or 3xx?\r\n\r\nWell, this library will throw an error.\r\nIn previous versions of this library, the behavior was different, but now we throw an error if the status does not indicate success.\r\n\r\nWhen it throws an error, the request will simply fail to process the event, and depending on how you set up your dead-letter queue or your retry police,\r\ncan be sent to dead-letter queue for you to check what happens or try again.\r\n\r\n## Batch Item Failures\r\n\r\nIf you enable this batch item failure option, to be able to partially return that some items failed to process, first configure your Adapter:\r\n\r\n```ts\r\nconst adapter = new DynamoDBAdapter({\r\n  batch: true,\r\n});\r\n```\r\n\r\nAnd then, just return the following JSON in the route that processes the DynamoDB event.\r\n\r\n```json\r\n{\r\n  \"batchItemFailures\": [\r\n    {\r\n        \"itemIdentifier\": \"id2\"\r\n    },\r\n    {\r\n        \"itemIdentifier\": \"id4\"\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\n> [Reference](https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html#services-ddb-batchfailurereporting)\r\n\r\n"
  },
  {
    "path": "www/docs/main/adapters/aws/event-bridge.mdx",
    "content": "---\r\ntitle: EventBridge (CloudWatch Events)\r\ndescription: See more about how to integrate with AWS EventBridge.\r\n---\r\n\r\nThe adapter to handle requests from [AWS EventBridge](https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents.html).\r\n\r\n:::info\r\n\r\nThe option of `responseWithErrors` is ignored by this adapter and we always call `resolver.fail` with the error.\r\n\r\n:::\r\n\r\n## Typescript\r\n\r\nTo correctly type your `body` when receiving the AWS EventBridge request, you must install `aws-lambda`:\r\n\r\n```bash\r\nnpm i --save-dev @types/aws-lambda\r\n```\r\n\r\nSo when getting the `body` you should use this type:\r\n\r\n```ts title=\"eventbridge.controller.ts\"\r\nimport type { EventBridgeEvent } from 'aws-lambda';\r\n```\r\n\r\nIf you want to integrate with Scheduled Expression, you can use this type:\r\n\r\n```ts title=\"eventbridge.controller.ts\"\r\nimport type { ScheduledEvent } from 'aws-lambda';\r\n```\r\n\r\n## About the adapter\r\n\r\nIn AWS EventBridge, you don't have requests, you just receive the info from Cloudwatch Events within `event` property of the handler.\r\n\r\nSo, in order to handle this adapter, by default we create a `POST` request to `/eventbridge` with the `body` being the `event` property as JSON.\r\n\r\n```json title=\"rds-eventbridge-event-example.json\"\r\n{\r\n    \"version\": \"0\",\r\n    \"id\": \"fe8d3c65-xmpl-c5c3-2c87-81584709a377\",\r\n    \"detail-type\": \"RDS DB Instance Event\",\r\n    \"source\": \"aws.rds\",\r\n    \"account\": \"123456789012\",\r\n    \"time\": \"2020-04-28T07:20:20Z\",\r\n    \"region\": \"us-east-2\",\r\n    \"resources\": [\r\n        \"arn:aws:rds:us-east-2:123456789012:db:rdz6xmpliljlb1\"\r\n    ],\r\n    \"detail\": {\r\n        \"EventCategories\": [\r\n            \"backup\"\r\n        ],\r\n        \"SourceType\": \"DB_INSTANCE\",\r\n        \"SourceArn\": \"arn:aws:rds:us-east-2:123456789012:db:rdz6xmpliljlb1\",\r\n        \"Date\": \"2020-04-28T07:20:20.112Z\",\r\n        \"Message\": \"Finished DB Instance backup\",\r\n        \"SourceIdentifier\": \"rdz6xmpliljlb1\"\r\n    }\r\n}\r\n```\r\n\r\nNormally, your framework will parse this JSON and return the parsed values as javascript objects.\r\n\r\n### Schedule Expression\r\n\r\nWith [Schedule Expression](https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents-expressions.html), you have the following JSON when the event is triggered:\r\n\r\n```json title=\"scheduled-eventbridge-event-example.json\"\r\n{\r\n  \"version\": \"0\",\r\n  \"account\": \"123456789012\",\r\n  \"region\": \"us-east-2\",\r\n  \"detail\": {},\r\n  \"detail-type\": \"Scheduled Event\",\r\n  \"source\": \"aws.events\",\r\n  \"time\": \"2019-03-01T01:23:45Z\",\r\n  \"id\": \"cdc73f9d-aea9-11e3-9d5a-835b769c0d9c\",\r\n  \"resources\": [\r\n    \"arn:aws:events:us-east-2:123456789012:rule/my-schedule\"\r\n  ]\r\n}\r\n```\r\n\r\nIt's good enough if you want to integrate with just one cron job, but what if you want more?\r\n\r\nOne option is to check the `resources` property, but I don't like that solution, so I'll introduce it to you in a way.\r\n\r\nWhen selecting the target as AWS Lambda, you can configure in `Additional Settings` the `input target` as [Input Transformer](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-transform-target-input.html),\r\nwith this option you can modify the above JSON into something different or add new properties.\r\n\r\nAfter clicking `Configure Input Transformer`, you can choose the `Scheduled Event` in the sample event to get an idea of what the event will look like after the transformation.\r\n\r\nIn the `Input Path` inside the Target Input Transformer you will put this json:\r\n\r\n```json title=\"input-path.json\"\r\n{\r\n  \"account\": \"$.account\",\r\n  \"detail-type\": \"$.detail-type\",\r\n  \"id\": \"$.id\",\r\n  \"region\": \"$.region\",\r\n  \"resources\": \"$.resources\",\r\n  \"source\": \"$.source\",\r\n  \"time\": \"$.time\",\r\n  \"version\": \"$.version\"\r\n}\r\n```\r\n\r\nAnd inside `Template`, you will put this json:\r\n\r\n```json\r\n{\r\n  \"version\": \"<version>\",\r\n  \"id\": \"<id>\",\r\n  \"detail-type\": \"<detail-type>\",\r\n  \"source\": \"<source>\",\r\n  \"account\": \"<account>\",\r\n  \"time\": \"<time>\",\r\n  \"region\": \"<region>\",\r\n  \"resources\": [],\r\n  \"detail\": {\r\n    \"action\": \"my_25min_cron\"\r\n  }\r\n}\r\n```\r\n\r\nDid you see the `action` inside the details? This property will be added when the event comes from Schedule Expression,\r\nwith this property you can differentiate which cron was called.\r\n\r\nInside your controller, you can write code like this:\r\n\r\n```ts title=\"event-bridge.controller.ts\"\r\nimport type { ScheduledEvent } from 'aws-lambda';\r\n\r\n// inside your controller method\r\ntype ScheduleEventWithAction = ScheduledEvent<{ action: 'my_25min_cron' | 'my_50min_cron' }>;\r\nconst scheduleEvent = request.body as unknown as ScheduleEventWithAction;\r\n\r\nswitch(scheduleEvent.detail.action) {\r\n  case 'my_25min_cron':\r\n    console.log('Your 25 min schedule expression was called.');\r\n    break;\r\n  case 'my_50min_cron':\r\n    console.log('Your 50 min schedule expression was called.');\r\n    break;\r\n  default:\r\n    console.error('The action was not recognized.');\r\n    break;\r\n}\r\n```\r\n\r\n## Customizing\r\n\r\nYou can change the HTTP Method and Path that will be used to create the request by sending `eventBridgeForwardMethod` and `eventBridgeForwardPath` inside [EventBridgeOptions](/docs/api/Adapters/AWS/EventBridgeAdapter/EventBridgeOptions).\r\n\r\n## Usage\r\n\r\nTo add support to AWS EventBridge you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { EventBridgeAdapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new DefaultHandler())\r\n  // .setFramework(new ExpressFramework())\r\n  // .setResolver(new PromiseResolver())\r\n  .addAdapter(new EventBridgeAdapter())\r\n  // customizing:\r\n  // .addAdapter(new EventBridgeAdapter({ eventBridgeForwardPath: '/prod/eventbridge', eventBridgeForwardMethod: 'PUT' }))\r\n  .build();\r\n```\r\n\r\n:::caution\r\n\r\nWhen you configure your API with some `basePath` like `/prod`, you should set `eventBridgeForwardPath` as `/prod/eventbridge` instead leave as default `/eventbridge`.\r\n\r\n:::\r\n\r\n## Security\r\n\r\nYou **MUST** check if the header `Host` contains the value of `events.amazonaws.com`.\r\n\r\nWithout checking this header, if you add this adapter and [AWS API Gateway V2](./api-gateway-v2) adapter, you will be vulnerable to attacks\r\nbecause anyone can create a `POST` request to `/eventbridge`.\r\n\r\n## What happens when my response status is different from 2xx or 3xx?\r\n\r\nWell, this library will throw an error.\r\nIn previous versions of this library, the behavior was different, but now we throw an error if the status does not indicate success.\r\n\r\nWhen it throws an error, the request will simply fail to process the event, and depending on how you set up your dead-letter queue or your retry police,\r\ncan be sent to dead-letter queue for you to check what happens or try again.\r\n"
  },
  {
    "path": "www/docs/main/adapters/aws/function-url.mdx",
    "content": "---\ntitle: Function URLs\ndescription: See more about how to integrate with AWS Lambda Function URLs\n---\n\nThe [AWS Lambda Function URLs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html) has the same API interface of [API Gateway V2](./api-gateway-v2),\nso you can use the [ApiGatewayV2Adapter](./api-gateway-v2#usage) to support it.\n\n```ts title=\"index.ts\"\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\nimport { ApiGatewayV2Adapter } from '@h4ad/serverless-adapter/adapters/aws';\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\nimport app from './app';\n\nexport const handler = ServerlessAdapter.new(app)\n  .setHandler(new DefaultHandler())\n  // .setFramework(new ExpressFramework())\n  // .setResolver(new PromiseResolver())\n  .addAdapter(new ApiGatewayV2Adapter())\n  // customizing:\n  // .addAdapter(new ApiGatewayV2Adapter({ stripBasePath: '/prod' }))\n  .build();\n```\n\n## AWS Lambda Response Streaming\n\nTo support response streaming, read the docs on [AwsStreamHandler](../../handlers/aws#aws-lambda-response-streaming).\n"
  },
  {
    "path": "www/docs/main/adapters/aws/lambda-edge.mdx",
    "content": "---\r\ntitle: Lambda@Edge\r\ndescription: See more about how to integrate with AWS Lambda@Edge.\r\n---\r\n\r\nThe adapter to handle requests from [AWS Lambda@Edge](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-at-the-edge.html).\r\n\r\nWe have two implementations that works with Lambda@Edge:\r\n\r\n## RequestLambdaEdgeAdapter\r\n\r\nThis is the most useful implementation as it allows you to return a response during `viewer-request` and `origin-request` events.\r\nAlso, this means that you cannot use this adapter to handle `viewer-response` and `origin-response` events.\r\n\r\nIn short, it works like when you deploy your code using Vercel and you have an `api` folder, but instead of being deployed to Vercel, it is deployed to Lambda@Edge.\r\n\r\n### Customizing\r\n\r\nYou can remove the base path with the `stripBasePath` option inside [RequestLambdaEdgeAdapterOptions](/docs/api/Adapters/AWS/RequestLambdaEdgeAdapter/RequestLambdaEdgeAdapterOptions).\r\n\r\n:::caution\r\n\r\nWhen configuring your API with some `basePath` such as `/api`, you must send the request on path `/api/my/path` or set `stripBasePath` to `/api`.\r\n\r\n:::\r\n\r\n### How to use\r\n\r\nTo add support to AWS Lambda@Edge you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { RequestLambdaEdgeAdapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new DefaultHandler())\r\n  // .setFramework(new ExpressFramework())\r\n  // .setResolver(new PromiseResolver())\r\n  .addAdapter(new RequestLambdaEdgeAdapter())\r\n  // customizing:\r\n  // .addAdapter(new RequestLambdaEdgeAdapter({ stripBasePath: '/api' }))\r\n  .build();\r\n```\r\n\r\n### Caution with limits\r\n\r\nAWS Lambda@Edge has some limits, and one of them is response size, which is 1MB for `origin-request` and 40KB for `viewer-request`, [see more here](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/edge-functions-restrictions.html).\r\n\r\n### `viewer request` or `source request`?\r\n\r\nI personally prefer using `origin-request` because it can return a larger response, plus you can configure the cache behavior to cache the response, which is not possible with `viewer-request`.\r\n\r\n### Cache\r\n\r\nAs I mentioned above, you can cache the response when using `origin-request`, the only problem if you set the default cache option it will cache everything!\r\n\r\nYou can control the cache timing by setting the `cache-control` header, but for `GET` and `HEAD` requests, even with `no-store` or `no-cache` set in `cache-control`, if you send the request fast enough it will return the value from the cache.\r\n\r\nThe `POST`, `DELETE`, etc... methods are not cached, so don't worry about them.\r\n\r\nIn resume, you can cache the response, but you need to know what you want to do and also understand how to set the cache switch correctly, so [read the docs](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ConfiguringCaching.html).\r\n\r\n## LambdaEdgeAdapter\r\n\r\nHonestly, I added this adapter because @vendia/serverless-adapter had already added support for Lambda Edge, but reading my implementation and @vendia's implementation, I never knew if it actually worked because I didn't test it on AWS.\r\n\r\nSo at the moment I'm not going to create any documentation and feel free to test this adapter and see how it behaves.\r\n\r\nYou can read the [source code here](https://github.com/H4ad/serverless-adapter/blob/main/src/adapters/aws/lambda-edge.adapter.ts) to see how the request and response are being assembled, as well as take a look at [LambdaEdgeAdapterOptions](/docs/api/Adapters/AWS/LambdaEdgeAdapter/LambdaEdgeAdapterOptions) to see what options you can pass.\r\n\r\nDespite being lazy to create Lambda Edge documentation, in the code I tried to add as many comments as possible to explain each option.\r\n"
  },
  {
    "path": "www/docs/main/adapters/aws/s3.mdx",
    "content": "---\r\ntitle: S3\r\ndescription: See more about how to integrate with AWS S3.\r\n---\r\n\r\nThe adapter to handle requests from [AWS S3](https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html).\r\n\r\n:::info\r\n\r\nThe option of `responseWithErrors` is ignored by this adapter and we always call `resolver.fail` with the error.\r\n\r\n:::\r\n\r\n## Typescript\r\n\r\nTo correctly type your `body` when receiving the AWS S3 request, you must install `aws-lambda`:\r\n\r\n```bash\r\nnpm i --save-dev @types/aws-lambda\r\n```\r\n\r\nSo when getting the `body` you should use this type:\r\n\r\n```ts title=\"s3.controller.ts\"\r\nimport type { S3Event } from 'aws-lambda';\r\n```\r\n\r\n## About the adapter\r\n\r\nIn AWS S3, you don't have requests, you just receive the records from the queue in the `event` property of the handler.\r\n\r\nSo, in order to handle this adapter, by default we create a `POST` request to `/s3` with the `body` being the `event` property as JSON.\r\n\r\n```json title=\"s3-event-example.json\"\r\n{\r\n  \"Records\": [\r\n    {\r\n      \"eventVersion\": \"2.1\",\r\n      \"eventSource\": \"aws:s3\",\r\n      \"awsRegion\": \"us-east-2\",\r\n      \"eventTime\": \"2019-09-03T19:37:27.192Z\",\r\n      \"eventName\": \"ObjectCreated:Put\",\r\n      \"userIdentity\": {\r\n        \"principalId\": \"AWS:AIDAINPONIXQXHT3IKHL2\"\r\n      },\r\n      \"requestParameters\": {\r\n        \"sourceIPAddress\": \"205.255.255.255\"\r\n      },\r\n      \"responseElements\": {\r\n        \"x-amz-request-id\": \"D82B88E5F771F645\",\r\n        \"x-amz-id-2\": \"vlR7PnpV2Ce81l0PRw6jlUpck7Jo5ZsQjryTjKlc5aLWGVHPZLj5NeC6qMa0emYBDXOo6QBU0Wo=\"\r\n      },\r\n      \"s3\": {\r\n        \"s3SchemaVersion\": \"1.0\",\r\n        \"configurationId\": \"828aa6fc-f7b5-4305-8584-487c791949c1\",\r\n        \"bucket\": {\r\n          \"name\": \"DOC-EXAMPLE-BUCKET\",\r\n          \"ownerIdentity\": {\r\n            \"principalId\": \"A3I5XTEXAMAI3E\"\r\n          },\r\n          \"arn\": \"arn:aws:s3:::lambda-artifacts-deafc19498e3f2df\"\r\n        },\r\n        \"object\": {\r\n          \"key\": \"b21b84d653bb07b05b1e6b33684dc11b\",\r\n          \"size\": 1305107,\r\n          \"eTag\": \"b21b84d653bb07b05b1e6b33684dc11b\",\r\n          \"sequencer\": \"0C0F6F405D6ED209E1\"\r\n        }\r\n      }\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\nNormally, your framework will parse this JSON and return the parsed values as javascript objects.\r\n\r\n## Customizing\r\n\r\nYou can change the HTTP Method and Path that will be used to create the request by sending `s3ForwardMethod` and `s3ForwardPath` inside [S3AdapterOptions](/docs/api/Adapters/AWS/S3Adapter/S3AdapterOptions).\r\n\r\n## Usage\r\n\r\nTo add support to AWS S3 you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { S3Adapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new DefaultHandler())\r\n  // .setFramework(new ExpressFramework())\r\n  // .setResolver(new PromiseResolver())\r\n  .addAdapter(new S3Adapter())\r\n  // customizing:\r\n  // .addAdapter(new S3Adapter({ s3ForwardPath: '/prod/s3', s3ForwardMethod: 'PUT' }))\r\n  .build();\r\n```\r\n\r\n:::caution\r\n\r\nWhen you configure your API with some `basePath` like `/prod`, you should set `s3ForwardPath` as `/prod/s3` instead leave as default `/s3`.\r\n\r\n:::\r\n\r\n## Security\r\n\r\nYou **MUST** check if the header `Host` contains the value of `s3.amazonaws.com`.\r\n\r\nWithout checking this header, if you add this adapter and [AWS API Gateway V2](./api-gateway-v2) adapter, you will be vulnerable to attacks\r\nbecause anyone can create a `POST` request to `/s3`.\r\n\r\n## What happens when my response status is different from 2xx or 3xx?\r\n\r\nWell, this library will throw an error.\r\nIn previous versions of this library, the behavior was different, but now we throw an error if the status does not indicate success.\r\n\r\nWhen it throws an error, the request will simply fail to process the event, and depending on how you set up your dead-letter queue or your retry police,\r\ncan be sent to dead-letter queue for you to check what happens or try again.\r\n"
  },
  {
    "path": "www/docs/main/adapters/aws/sns.mdx",
    "content": "---\r\ntitle: SNS\r\ndescription: See more about how to integrate with AWS SNS.\r\n---\r\n\r\nThe adapter to handle requests from [AWS SNS](https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html).\r\n\r\n:::info\r\n\r\nThe option of `responseWithErrors` is ignored by this adapter and we always call `resolver.fail` with the error.\r\n\r\n:::\r\n\r\n## Typescript\r\n\r\nTo correctly type your `body` when receiving the AWS SNS request, you must install `aws-lambda`:\r\n\r\n```bash\r\nnpm i --save-dev @types/aws-lambda\r\n```\r\n\r\nSo when getting the `body` you should use this type:\r\n\r\n```ts title=\"sns.controller.ts\"\r\nimport type { SNSEvent } from 'aws-lambda';\r\n```\r\n\r\n## About the adapter\r\n\r\nIn AWS SNS, you don't have requests, you just receive the records in the `event` property of the handler.\r\n\r\nSo, to be able to handle this adapter, by default we create a `POST` request to `/sns` with the `body` being the `event` property as JSON.\r\n\r\n```json title=\"sns-event-example.json\"\r\n{\r\n  \"Records\": [\r\n    {\r\n      \"EventVersion\": \"1.0\",\r\n      \"EventSubscriptionArn\": \"arn:aws:sns:us-east-2:123456789012:sns-lambda:21be56ed-a058-49f5-8c98-aedd2564c486\",\r\n      \"EventSource\": \"aws:sns\",\r\n      \"Sns\": {\r\n        \"SignatureVersion\": \"1\",\r\n        \"Timestamp\": \"2019-01-02T12:45:07.000Z\",\r\n        \"Signature\": \"tcc6faL2yUC6dgZdmrwh1Y4cGa/ebXEkAi6RibDsvpi+tE/1+82j...65r==\",\r\n        \"SigningCertUrl\": \"https://sns.us-east-2.amazonaws.com/SimpleNotificationService-ac565b8b1a6c5d002d285f9598aa1d9b.pem\",\r\n        \"MessageId\": \"95df01b4-ee98-5cb9-9903-4c221d41eb5e\",\r\n        \"Message\": \"Hello from SNS!\",\r\n        \"MessageAttributes\": {\r\n          \"Test\": {\r\n            \"Type\": \"String\",\r\n            \"Value\": \"TestString\"\r\n          },\r\n          \"TestBinary\": {\r\n            \"Type\": \"Binary\",\r\n            \"Value\": \"TestBinary\"\r\n          }\r\n        },\r\n        \"Type\": \"Notification\",\r\n        \"UnsubscribeUrl\": \"https://sns.us-east-2.amazonaws.com/?Action=Unsubscribe&amp;SubscriptionArn=arn:aws:sns:us-east-2:123456789012:test-lambda:21be56ed-a058-49f5-8c98-aedd2564c486\",\r\n        \"TopicArn\":\"arn:aws:sns:us-east-2:123456789012:sns-lambda\",\r\n        \"Subject\": \"TestInvoke\"\r\n      }\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\nNormally, your framework will parse this JSON and return the parsed values as javascript objects.\r\n\r\n## Customizing\r\n\r\nYou can change the HTTP Method and Path that will be used to create the request by sending `snsForwardMethod` and `snsForwardPath` inside [SNSAdapterOptions](/docs/api/Adapters/AWS/SNSAdapter/SNSAdapterOptions).\r\n\r\n## Usage\r\n\r\nTo add support to AWS SNS you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { SNSAdapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new DefaultHandler())\r\n  // .setFramework(new ExpressFramework())\r\n  // .setResolver(new PromiseResolver())\r\n  .addAdapter(new SNSAdapter())\r\n  // customizing:\r\n  // .addAdapter(new SNSAdapter({ snsForwardMethod: '/prod/sns', snsForwardPath: 'PUT' }))\r\n  .build();\r\n```\r\n\r\n:::caution\r\n\r\nWhen you configure your API with some `basePath` like `/prod`, you should set `snsForwardPath` as `/prod/sns` instead leave as default `/sns`.\r\n\r\n:::\r\n\r\n## Security\r\n\r\nYou **MUST** check if the header `Host` contains the value of `sns.amazonaws.com`.\r\n\r\nWithout checking this header, if you add this adapter and [AWS API Gateway V2](./api-gateway-v2) adapter, you will be vulnerable to attacks\r\nbecause anyone can create a `POST` request to `/sns`.\r\n\r\n## What happens when my response status is different from 2xx or 3xx?\r\n\r\nWell, this library will throw an error.\r\nIn previous versions of this library, the behavior was different, but now we throw an error if the status does not indicate success.\r\n\r\nWhen it throws an error, the request will simply fail to process the event, and depending on how you set up your dead-letter queue or your retry police,\r\ncan be sent to dead-letter queue for you to check what happens or try again.\r\n"
  },
  {
    "path": "www/docs/main/adapters/aws/sqs.mdx",
    "content": "---\r\ntitle: SQS\r\ndescription: See more about how to integrate with AWS SQS.\r\n---\r\n\r\nThe adapter to handle requests from [AWS SQS](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html).\r\n\r\n:::info\r\n\r\nThe option of `responseWithErrors` is ignored by this adapter and we always call `resolver.fail` with the error.\r\n\r\n:::\r\n\r\n## Typescript\r\n\r\nTo correctly type your `body` when receiving the AWS SQS request, you must install `aws-lambda`:\r\n\r\n```bash\r\nnpm i --save-dev @types/aws-lambda\r\n```\r\n\r\nSo when getting the `body` you should use this type:\r\n\r\n```ts title=\"sqs.controller.ts\"\r\nimport type { SQSEvent } from 'aws-lambda';\r\n```\r\n\r\n## About the adapter\r\n\r\nIn AWS SQS, you don't have requests, you just receive the records from the queue in the `event` property of the handler.\r\n\r\nSo, in order to handle this adapter, by default we create a `POST` request to `/sqs` with the `body` being the `event` property as JSON.\r\n\r\n```json title=\"sqs-event-example.json\"\r\n{\r\n    \"Records\": [\r\n        {\r\n            \"messageId\": \"059f36b4-87a3-44ab-83d2-661975830a7d\",\r\n            \"receiptHandle\": \"AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...\",\r\n            \"body\": \"Test message.\",\r\n            \"attributes\": {\r\n                \"ApproximateReceiveCount\": \"1\",\r\n                \"SentTimestamp\": \"1545082649183\",\r\n                \"SenderId\": \"AIDAIENQZJOLO23YVJ4VO\",\r\n                \"ApproximateFirstReceiveTimestamp\": \"1545082649185\"\r\n            },\r\n            \"messageAttributes\": {},\r\n            \"md5OfBody\": \"e4e68fb7bd0e697a0ae8f1bb342846b3\",\r\n            \"eventSource\": \"aws:sqs\",\r\n            \"eventSourceARN\": \"arn:aws:sqs:us-east-2:123456789012:my-queue\",\r\n            \"awsRegion\": \"us-east-2\"\r\n        }\r\n    ]\r\n}\r\n```\r\n\r\nNormally, your framework will parse this JSON and return the parsed values as javascript objects.\r\n\r\n## Customizing\r\n\r\nYou can change the HTTP Method and Path that will be used to create the request by sending `sqsForwardMethod` and `sqsForwardPath` inside [SQSAdapterOptions](/docs/api/Adapters/AWS/SQSAdapter/SQSAdapterOptions).\r\n\r\n## Usage\r\n\r\nTo add support to AWS SQS you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { SQSAdapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new DefaultHandler())\r\n  // .setFramework(new ExpressFramework())\r\n  // .setResolver(new PromiseResolver())\r\n  .addAdapter(new SQSAdapter())\r\n  // customizing:\r\n  // .addAdapter(new SQSAdapter({ sqsForwardPath: '/prod/sqs', sqsForwardMethod: 'PUT' }))\r\n  .build();\r\n```\r\n\r\n:::caution\r\n\r\nWhen you configure your API with some `basePath` like `/prod`, you should set `sqsForwardPath` as `/prod/sqs` instead leave as default `/sqs`.\r\n\r\n:::\r\n\r\n## Security\r\n\r\nYou **MUST** check if the header `Host` contains the value of `sqs.amazonaws.com`.\r\n\r\nWithout checking this header, if you add this adapter and [AWS API Gateway V2](./api-gateway-v2) adapter, you will be vulnerable to attacks\r\nbecause anyone can create a `POST` request to `/sqs`.\r\n\r\n## What happens when my response status is different from 2xx or 3xx?\r\n\r\nWell, this library will throw an error.\r\nIn previous versions of this library, the behavior was different, but now we throw an error if the status does not indicate success.\r\n\r\nWhen it throws an error, the request will simply fail to process the event, and depending on how you set up your dead-letter queue or your retry police,\r\ncan be sent to dead-letter queue for you to check what happens or try again.\r\n\r\n## Batch Item Failures\r\n\r\nIf you enable this batch item failure option, to be able to partially return that some items failed to process, first configure your Adapter:\r\n\r\n```ts\r\nconst adapter = new SQSAdapter({\r\n  batch: true,\r\n});\r\n```\r\n\r\nAnd then, just return the following JSON in the route that processes the SQS event.\r\n\r\n```json\r\n{\r\n  \"batchItemFailures\": [\r\n    {\r\n        \"itemIdentifier\": \"id2\"\r\n    },\r\n    {\r\n        \"itemIdentifier\": \"id4\"\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\n> [Reference](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html#services-sqs-batchfailurereporting)\r\n\r\n"
  },
  {
    "path": "www/docs/main/adapters/azure/http-trigger-v4.mdx",
    "content": "---\r\ntitle: Http Trigger V4\r\ndescription: See more about how to integrate with Azure Http Trigger V4\r\n---\r\n\r\n:::caution Attention\r\n\r\nCheck the [AzureHandler](../../handlers/azure) docs to make sure you have all the necessary settings to work with this adapter.\r\n\r\n:::\r\n\r\nThe adapter to handle requests from [Azure Http Trigger V4](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook-trigger?tabs=in-process%2Cfunctionsv2&pivots=programming-language-javascript).\r\n\r\n:::info\r\n\r\nWhen an error is thrown during forwarding and the `responseWithErrors` option is `true`, we return a 500 status WITH error stack in the response.\r\n\r\n:::\r\n\r\n## Requirements\r\n\r\nThis adapter was created to work with runtine 4.x, [see the docs](https://docs.microsoft.com/en-us/azure/azure-functions/functions-versions?tabs=azure-cli%2Cin-process%2Cv4&pivots=programming-language-javascript#changing-version-of-apps-in-azure)\r\nto know more about how to check and change the version if you need.\r\n\r\nIn theory, this adapter works with runtime 3.x but I haven't tested it.\r\n\r\n## About the adapter\r\n\r\nThis adapter transforms every request coming from Azure Http Trigger V4 into an HTTP request to your framework.\r\n\r\n```json title=\"azure-http-trigger-event-example.json\"\r\n{\r\n  \"method\":\"POST\",\r\n  \"url\":\"https://serverless-adapter.azurewebsites.net/api/test-serverless-adapter/events?code=sE_d8h7XJ4YYsGJ7mgVta_t-32323%253D%253D\",\r\n  \"headers\":{\r\n    \"accept\":\"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\",\r\n    \"accept-encoding\":\"gzip, deflate, br\",\r\n    \"accept-language\":\"pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,bg;q=0.6\",\r\n    \"cache-control\":\"max-age=0\",\r\n    \"host\":\"serverless-adapter.azurewebsites.net\",\r\n    \"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36\",\r\n    \"sec-ch-ua\":\"\\\".Not/A)Brand\\\";v=\\\"99\\\", \\\"Google Chrome\\\";v=\\\"103\\\", \\\"Chromium\\\";v=\\\"103\\\"\",\r\n    \"sec-ch-ua-mobile\":\"?0\",\r\n    \"sec-ch-ua-platform\":\"\\\"Linux\\\"\",\r\n    \"client-ip\":\"2.3.3.3:30750\",\r\n    \"x-forwarded-proto\":\"https\",\r\n    \"x-appservice-proto\":\"https\",\r\n    \"x-arr-ssl\":\"2048|256|CN=Microsoft Azure TLS Issuing CA 01, O=Microsoft Corporation, C=US|CN=*.azurewebsites.net, O=Microsoft Corporation, L=Redmond, S=WA, C=US\",\r\n    \"x-forwarded-tlsversion\":\"1.2\",\r\n    \"x-forwarded-for\":\"3.3.3.3:49196\",\r\n    \"x-original-url\":\"/api/test-serverless-adapter?code=sE_d8h7XJ4YYsGJ7mgVta_t-32323%3D%3D\",\r\n    \"x-waws-unencoded-url\":\"/api/test-serverless-adapter?code=sE_d8h7XJ4YYsGJ7mgVta_t-32323%3D%3D\",\r\n    \"disguised-host\":\"serverless-adapter.azurewebsites.net\"\r\n  },\r\n  \"query\":{\r\n    \"code\":\"sE_d8h7XJ4YYsGJ7mgVta_t-32323%3D%3D\"\r\n  },\r\n  \"params\":{},\r\n  \"body\":{\r\n    \"name\":\"H4ad Event\"\r\n  },\r\n  \"rawBody\":\"{\\\"name\\\":\\\"H4ad Event\\\"}\",\r\n  \"user\":null\r\n}\r\n```\r\n\r\nSo, to add support to the above request, we must have registered the `/api/test-serverless-adapter/events` route as `POST` and when Http Trigger sends this event, you will get:\r\n\r\n- `body`: `{\"name\":\"H4ad Event\"}`\r\n- `queryString`: `code=sE_d8h7XJ4YYsGJ7mgVta_t-32323%3D%3D`\r\n\r\n## Customizing\r\n\r\nYou can strip base path with the option `stripBasePath` inside [HttpTriggerV4AdapterOptions](/docs/api/Adapters/Azure/HttpTriggerV4Adapter/HttpTriggerV4AdapterOptions).\r\n\r\n:::tip\r\n\r\nYou can configure this option based on your api base url like: `/api/test-serverless-adapter`, then the request coming from `/api/test-serverless-adapter/events`\r\nwill be transformed into `/events`.\r\n\r\n:::\r\n\r\n## Usage\r\n\r\nTo add support to Azure Http Trigger you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { AzureHandler } from '@h4ad/serverless-adapter/handlers/azure';\r\nimport { PromiseResolver } from '@h4ad/serverless-adapter/resolvers/promise';\r\nimport { HttpTriggerV4Adapter } from '@h4ad/serverless-adapter/adapters/azure';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new AzureHandler())\r\n  // .setFramework(new ExpressFramework())\r\n  .setResolver(new PromiseResolver())\r\n  .addAdapter(new HttpTriggerV4Adapter())\r\n  // customizing:\r\n  // .addAdapter(new HttpTriggerV4Adapter({ stripBasePath: '/api/test-serverless-adapter' }))\r\n  .build();\r\n```\r\n\r\n:::caution\r\n\r\nYou MUST use the [PromiseResolver](../../resolvers/promise) combined with [AzureHandler](../../handlers/azure) to make this adapter work.\r\n\r\n:::\r\n\r\n## Credits\r\n\r\nThis handler was created inspired by code written by [@Shamshiel](https://github.com/Shamshiel) and [@zachabney](https://github.com/zachabney),\r\nthank you very much to them!\r\n\r\n"
  },
  {
    "path": "www/docs/main/adapters/digital-ocean/http-function.mdx",
    "content": "---\r\ntitle: Http Function\r\ndescription: See more about how to integrate with DigitalOcean Functions\r\n---\r\n\r\n:::caution Attention\r\n\r\nCheck the [DigitalOceanHandler](../../handlers/digital-ocean) docs to make sure you have all the necessary settings to work with this adapter.\r\n\r\n:::\r\n\r\nThe adapter to handle requests from [DigitalOcean Functions](https://docs.digitalocean.com/products/functions/quickstart/sample-functions/).\r\n\r\n:::info\r\n\r\nWhen an error is thrown during forwarding and the `responseWithErrors` option is `true`, we return a 500 status WITH error stack in the response.\r\n\r\n:::\r\n\r\n## Requirements\r\n\r\nWhen you work with DigitalOcean Functions, in the root of your repository you will have a file called `project.yml` which is used\r\nto determine the structure of your functions and will be used to deploy your code to DigitalOcean.\r\n\r\nTo this library understand the requests coming from DigitalOcean, you need to modify the default code of `project.yml`:\r\n\r\n```diff\r\npackages:\r\n  - name: [name-of-your-api]\r\n    functions:\r\n      - name: 'prod'\r\n        main: ''\r\n        runtime: 'nodejs:18'\r\n-        web: true\r\n+        web: 'raw'\r\n```\r\n\r\n## About the adapter\r\n\r\nThis adapter transforms every request coming from DigitalOcean Functions into an HTTP request to your framework.\r\n\r\n```json title=\"digital-ocean-http-function-event-example.json\"\r\n{\r\n  \"__ow_method\": \"post\",\r\n  \"__ow_query\": \"potato=true\",\r\n  \"__ow_body\": \"{\\\"test\\\":true}\",\r\n  \"__ow_headers\": {\r\n    \"accept\": \"*/*\",\r\n    \"accept-encoding\": \"gzip\",\r\n    \"cdn-loop\": \"cloudflare\",\r\n    \"cf-connecting-ip\": \"45.444.444.444\",\r\n    \"cf-ipcountry\": \"BR\",\r\n    \"cf-ray\": \"xxxxxxxxxxx-GRU\",\r\n    \"cf-visitor\": \"{\\\"scheme\\\":\\\"https\\\"}\",\r\n    \"host\": \"ccontroller\",\r\n    \"user-agent\": \"insomnia/2022.4.2\",\r\n    \"x-custom\": \"potato\",\r\n    \"x-forwarded-for\": \"45.444.444.444\",\r\n    \"x-forwarded-proto\": \"https\",\r\n    \"x-request-id\": \"xxxxxxxxxxxxxxxx\"\r\n  },\r\n  \"__ow_path\": \"/store\"\r\n}\r\n```\r\n\r\nSo, to add support to the above request, we must have registered the `/store` route as `POST` and when DigitalOcean sends this event, you will get:\r\n\r\n- `body`: `{\"test\":true}`\r\n- `queryString`: `potato=true`\r\n\r\n## Customizing\r\n\r\nYou can strip base path with the option `stripBasePath` inside [HttpFunctionAdapterOptions](/docs/api/Adapters/Digital%20Ocean/HttpFunctionAdapter/HttpFunctionAdapterOptions).\r\n\r\n:::tip\r\n\r\nYou can configure this option based on your api base url like: `/api/test-serverless-adapter`, then the request coming from `/api/test-serverless-adapter/events`\r\nwill be transformed into `/events`.\r\n\r\n:::\r\n\r\n## Usage\r\n\r\nTo add support to DigitalOcean Functions you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { DigitalOceanHandler } from '@h4ad/serverless-adapter/handlers/digital-ocean';\r\nimport { PromiseResolver } from '@h4ad/serverless-adapter/resolvers/promise';\r\nimport { HttpFunctionAdapter } from '@h4ad/serverless-adapter/adapters/digital-ocean';\r\nimport app from './app';\r\n\r\nexport const main = ServerlessAdapter.new(app)\r\n  .setHandler(new DigitalOceanHandler())\r\n  .setResolver(new PromiseResolver())\r\n  // continue to set the other options here.\r\n  // .setFramework(new ExpressFramework())\r\n  .addAdapter(new HttpFunctionAdapter())\r\n  .build();\r\n```\r\n\r\n## Examples\r\n\r\nYou can see examples of how to use [here](https://github.com/H4ad/serverless-adapter-examples).\r\n"
  },
  {
    "path": "www/docs/main/adapters/firebase.mdx",
    "content": "---\ntitle: Firebase\ndescription: See more about how to integrate with Firebase.\n---\n\nTo integrate with Firebase, see the docs about [Firebase Handler](../handlers/firebase).\n"
  },
  {
    "path": "www/docs/main/adapters/huawei/huawei-api-gateway.mdx",
    "content": "---\r\ntitle: Huawei Api Gateway\r\ndescription: See more about how to integrate with Api Gateway.\r\n---\r\n\r\nThis adapter add support to [Huawei Api Gateway](https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0102.html#functiongraph_02_0102__li5178638110137) inside [Huawei Function Graph](https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0101.html).\r\n\r\n## About the Adapter\r\n\r\nWhen you receive an `POST` request inside path `/users`, this adapter will forward that request to your framework,\r\nso you can just plug this adapter and doesn't need any configuration to work.\r\n\r\nTo see which options you can customize, see the [HuaweiApiGatewayOptions](/docs/api/Adapters/Huawei/HuaweiApiGatewayAdapter/HuaweiApiGatewayOptions) interface.\r\n\r\n## Usage\r\n\r\nTo add support to Api Gateway you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { HuaweiApiGatewayAdapter } from '@h4ad/serverless-adapter/adapters/huawei';\r\nimport { ExpressFramework } from '@h4ad/serverless-adapter/frameworks/express';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport { CallbackResolver } from '@h4ad/serverless-adapter/resolvers/callback';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setFramework(new ExpressFramework())\r\n  .setHandler(new DefaultHandler())\r\n  .setResolver(new CallbackResolver())\r\n  .addAdapter(new HuaweiApiGatewayAdapter())\r\n  .build();\r\n```\r\n\r\n:::caution One important thing\r\n\r\nYou must use the callback resolver because I couldn't get it to work with the PromiseResolver.\r\nMaybe it's a bug in the library or something specific in Huawei, if you have a hint please create an issue.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/advanced/adapters/creating-an-adapter.mdx",
    "content": "---\r\ntitle: Creating an Adapter\r\nposition: 2\r\n---\r\n\r\nAs we saw in [Introduction](/docs/main/intro), you are already familiar with adapter methods.\r\n\r\nIn this chapter, we will create a new adapter to implement the [AWS Api Gateway V2](/docs/main/adapters/aws/api-gateway-v2)\r\nthat has the request and response in the following format:\r\n\r\n## Request and Response\r\n\r\n```json title=\"request.json\"\r\n{\r\n  \"version\": \"2.0\",\r\n  \"routeKey\": \"$default\",\r\n  \"rawPath\": \"/my/path\",\r\n  \"rawQueryString\": \"parameter1=value1&parameter1=value2&parameter2=value\",\r\n  \"cookies\": [\r\n    \"cookie1\",\r\n    \"cookie2\"\r\n  ],\r\n  \"headers\": {\r\n    \"header1\": \"value1\",\r\n    \"header2\": \"value1,value2\"\r\n  },\r\n  \"queryStringParameters\": {\r\n    \"parameter1\": \"value1,value2\",\r\n    \"parameter2\": \"value\"\r\n  },\r\n  \"requestContext\": {\r\n    \"accountId\": \"123456789012\",\r\n    \"apiId\": \"api-id\",\r\n    \"authentication\": {\r\n      \"clientCert\": {\r\n        \"clientCertPem\": \"CERT_CONTENT\",\r\n        \"subjectDN\": \"www.example.com\",\r\n        \"issuerDN\": \"Example issuer\",\r\n        \"serialNumber\": \"a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1\",\r\n        \"validity\": {\r\n          \"notBefore\": \"May 28 12:30:02 2019 GMT\",\r\n          \"notAfter\": \"Aug  5 09:36:04 2021 GMT\"\r\n        }\r\n      }\r\n    },\r\n    \"authorizer\": {\r\n      \"jwt\": {\r\n        \"claims\": {\r\n          \"claim1\": \"value1\",\r\n          \"claim2\": \"value2\"\r\n        },\r\n        \"scopes\": [\r\n          \"scope1\",\r\n          \"scope2\"\r\n        ]\r\n      }\r\n    },\r\n    \"domainName\": \"id.execute-api.us-east-1.amazonaws.com\",\r\n    \"domainPrefix\": \"id\",\r\n    \"http\": {\r\n      \"method\": \"POST\",\r\n      \"path\": \"/my/path\",\r\n      \"protocol\": \"HTTP/1.1\",\r\n      \"sourceIp\": \"IP\",\r\n      \"userAgent\": \"agent\"\r\n    },\r\n    \"requestId\": \"id\",\r\n    \"routeKey\": \"$default\",\r\n    \"stage\": \"$default\",\r\n    \"time\": \"12/Mar/2020:19:03:58 +0000\",\r\n    \"timeEpoch\": 1583348638390\r\n  },\r\n  \"body\": \"Hello from Lambda\",\r\n  \"pathParameters\": {\r\n    \"parameter1\": \"value1\"\r\n  },\r\n  \"isBase64Encoded\": false,\r\n  \"stageVariables\": {\r\n    \"stageVariable1\": \"value1\",\r\n    \"stageVariable2\": \"value2\"\r\n  }\r\n}\r\n```\r\n\r\n\r\n```json title=\"response.json\"\r\n{\r\n    \"isBase64Encoded\": true,\r\n    \"statusCode\": 201,\r\n    \"headers\": { \"headername\": \"headervalue\" },\r\n    \"multiValueHeaders\": { \"headername\": [\"headervalue\", \"headervalue2\"] },\r\n    \"body\": \"Done\"\r\n}\r\n```\r\n\r\n## Creating the class\r\n\r\nFirst, we need to create our new adapter class, let's define it as:\r\n\r\n```typescript title=\"api-gateway-v2.adapter.ts\"\r\nimport type { APIGatewayProxyEventV2, Context } from 'aws-lambda';\r\nimport type { APIGatewayProxyStructuredResultV2 } from 'aws-lambda/trigger/api-gateway-proxy';\r\nimport { AdapterContract } from '@h4ad/serverless-adapter/contracts';\r\n\r\nexport class ApiGatewayV2Adapter implements AdapterContract<APIGatewayProxyEventV2, Context, APIGatewayProxyStructuredResultV2> {}\r\n```\r\n\r\nThe interface we need to implement is [AdapterContract](/docs/api/Contracts/AdapterContract) which takes 3 generic arguments:\r\nthe event sent by the event source, the context of the serverless environment, and the response that the event source understands.\r\n\r\n## Implementing the `getAdapterName` method\r\n\r\nThis is the easiest method to implement, we can do it as follows:\r\n\r\n```typescript title=\"api-gateway-v2.adapter.ts\"\r\npublic getAdapterName(): string {\r\n  return ApiGatewayV2Adapter.name;\r\n}\r\n```\r\n\r\n## Implementing the `canHandle` method\r\n\r\nWhen we implement this method, we must study the request event to know which properties are always sent by the event source,\r\nin case of [AWS Api Gateway V2](/docs/main/adapters/aws/api-gateway-v2), the most important ones are `requestContext` and `version` and\r\nchecking that the value of `version` is equal to `2.0`.\r\n\r\nThis way, we can implement if the event was sent from [AWS Api Gateway V2](/docs/main/adapters/aws/api-gateway-v2) as follows:\r\n\r\n```typescript title=\"api-gateway-v2.adapter.ts\"\r\npublic canHandle(event: unknown): event is APIGatewayProxyEventV2 {\r\n  const apiGatewayEvent = event as Partial<APIGatewayProxyEventV2> & {\r\n    version?: string;\r\n  };\r\n\r\n  // this basically will verify if:\r\n  // - if event has requestContext\r\n  // - if event has version property equal to 2.0\r\n  // if both are true, then we do double bang\r\n  // just to make sure we return boolean\r\n  return !!(\r\n    apiGatewayEvent?.requestContext && apiGatewayEvent.version === '2.0'\r\n  );\r\n}\r\n```\r\n\r\n## Implementing the `getRequest` method\r\n\r\nIn this method, we need to return the [AdapterRequest](/docs/api/Contracts/AdapterContract/AdapterRequest) interface,\r\nto understand better what we need to return, let's deep into to know more about them.\r\n\r\n### `method`\r\n\r\nThe HTTP Method to use to create the request to the framework.\r\n\r\nIn [AWS Api Gateway V2](/docs/main/adapters/aws/api-gateway-v2) we can take the method from `APIGatewayProxyEventV2`,\r\naccessing the `method` property inside the `http` object that is inside the `requestContext`, the code will look like this:\r\n\r\n```typescript title=\"api-gateway-v2.adapter.ts\"\r\nconst method = event.requestContext.http.method;\r\n```\r\n\r\n:::tip\r\n\r\nIn some cases, you may not have this information from events such as SQS,\r\nin these specific cases you need to provide a way to control the path,\r\nwe recommend you provide a default option and provide a way for the user to customize,\r\nsuch as the implementation of [AWS SQS](/docs/main/adapters/aws/sqs).\r\n\r\n:::\r\n\r\n### `path`\r\n\r\nThe path to use to create the request to the framework.\r\n\r\nIn the [AWS Api Gateway V2](/docs/main/adapters/aws/api-gateway-v2), we can grab the path from `APIGatewayProxyEventV2`,\r\nacessing the property `rawPath` and combining with `rawQueryString`.\r\n\r\nFortunately, this operation is so common that we provide a function to help you with this operation, see above:\r\n\r\n```typescript title=\"api-gateway-v2.adapter.ts\"\r\nimport { getPathWithQueryStringParams } from '@h4ad/serverless-adapter';\r\n\r\n// ...\r\n// inside the function `getRequest`\r\nconst path = event.rawPath;\r\nconst queryParams = event.rawQueryString;\r\n\r\nconst pathWithQueryParams = getPathWithQueryStringParams(path, queryParams);\r\n```\r\n\r\n:::info\r\n\r\nThis implementation deviates from the original implementation for educational purposes only.\r\nSee the original implementation [here](https://github.com/H4ad/serverless-adapter/blob/main/src/adapters/aws/api-gateway-v2.adapter.ts#L194-L210).\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nIn some cases, you may not have this information from events such as SQS,\r\nin these specific cases you need to provide a way to control the path,\r\nwe recommend you provide a default option and provide a way for the user to customize,\r\nsuch as the implementation of [AWS SQS](/docs/main/adapters/aws/sqs).\r\n\r\n:::\r\n\r\n### `headers`\r\n\r\nThe headers to use to create the request to the framework.\r\n\r\nIn the [AWS Api Gateway V2](/docs/main/adapters/aws/api-gateway-v2), we can grab the headers from `APIGatewayProxyEventV2`,\r\nacessing the property `headers`.\r\n\r\nBut not only need to pass the property `headers`, we need to take care of headers not being like `\"accept-lang\": ['pt-BR', 'en-US']`,\r\nso we will use the helper function `getFlattenedHeadersMap`.\r\n\r\n```ts\r\nconst headers = getFlattenedHeadersMap(event.headers, ',', true);\r\n\r\n// this is a implementation detail for api gateway v2,\r\n// the cookies is sent from another property instead being\r\n// sent inside headers property\r\nif (event.cookies)\r\n  headers.cookie = event.cookies.join('; ');\r\n```\r\n\r\n:::tip\r\n\r\nIn some cases, you may not have this information from events such as SQS,\r\nin these specific cases you can just mock the headers with default values,\r\nsuch as the implementation of [AWS SQS](/docs/main/adapters/aws/sqs).\r\n\r\n:::\r\n\r\n### `body`\r\n\r\nThe body as buffer to use to create the request to the framework\r\n\r\nWell, the body actually can be anything you want, sometimes you will receive a JSON (eg: Api Gateway), Base64 or just plain javascript objects (eg: AWS SQS).ts\r\n\r\nIn the [AWS Api Gateway V2](/docs/main/adapters/aws/api-gateway-v2), we can grab the body from `APIGatewayProxyEventV2`,\r\nacessing the property `body` and use the property `isBase64Encoded` to determine if the body is base64.\r\n\r\nTo help to transform the body from JSON or base64 to Buffer, we have the helper [getEventBodyAsBuffer](/docs/api/Core/getEventBodyAsBuffer).\r\n\r\nThe code will look like this:\r\n\r\n```ts\r\nlet body: Buffer | undefined;\r\n\r\nif (event.body) {\r\n  const [bufferBody, contentLength] = getEventBodyAsBuffer(\r\n    event.body,\r\n    event.isBase64Encoded,\r\n  );\r\n\r\n  body = bufferBody;\r\n  headers['content-length'] = String(contentLength);\r\n}\r\n```\r\n\r\n:::important\r\n\r\nYou need to set the `content-length` header to the value returned by the `getEventBodyAsBuffer` function.\r\n\r\n:::\r\n\r\n### `remoteAddress`\r\n\r\nThe remote address (client ip) to use to create the request to the framework\r\n\r\nIn the [AWS Api Gateway V2](/docs/main/adapters/aws/api-gateway-v2), we can grab the remote address from `APIGatewayProxyEventV2`,\r\nacessing the property `requestContext.http.sourceIp`.\r\n\r\n```ts\r\nconst remoteAddress = event.requestContext.http.sourceIp;\r\n```\r\n\r\n### `host` and `hostname`\r\n\r\nActually these two properties are not used by the library, so you can just ignore.\r\n\r\n## Implementing the `getResponse` method\r\n\r\nMaps the response of the framework to a payload that serverless can handle.\r\n\r\nIn other words, do you remember the json from the answer at the beginning of this tutorial?\r\n\r\nSo you need to return this json and let's see how we can map your function to this response:\r\n\r\n```ts title=\"api-gateway-v2.adapter.ts\"\r\npublic getResponse({\r\n  headers: responseHeaders,\r\n  body,\r\n  isBase64Encoded,\r\n  statusCode,\r\n  response,\r\n}: GetResponseAdapterProps<APIGatewayProxyEventV2>): APIGatewayProxyStructuredResultV2 {\r\n  const headers = getFlattenedHeadersMap(responseHeaders);\r\n  const multiValueHeaders = getMultiValueHeadersMap(responseHeaders);\r\n\r\n  // I removed content encoding checks for learning purposes only\r\n  // but in the original version we need to check more things here.\r\n\r\n  const cookies = multiValueHeaders['set-cookie'];\r\n\r\n  if (headers) delete headers['set-cookie'];\r\n\r\n  return {\r\n    statusCode,\r\n    body,\r\n    headers,\r\n    isBase64Encoded,\r\n    cookies,\r\n  };\r\n}\r\n```\r\n\r\nWhy did I put all the code? Because in the response, I don't have much to explain because each adapter will have your own implementation for this function.\r\n\r\n[AWS SQS](/docs/main/adapters/aws/sqs) for example, they don't need to return anything, so the implementation is:\r\n\r\n```ts title=\"sqs.adapter.ts\"\r\npublic getResponse(): IEmptyResponse {\r\n  return EmptyResponse;\r\n}\r\n```\r\n\r\nSo look closely at the event source documents you are creating the adapter for and try to map as many properties as possible to the properties that the library sends you.\r\n\r\n:::tip\r\n\r\nYou can check the [GetResponseAdapterProps](/docs/api/Contracts/AdapterContract/GetResponseAdapterProps) to check which data you have from the response of the framework.\r\n\r\n:::\r\n\r\n## Implementing the `onErrorWhileForwarding` method\r\n\r\nWhen an error occurs while forwarding the request to the framework.ts\r\n\r\nWell, errors can happen and we need to have a way to handle those cases to not messup and not have any information about the error.ts\r\n\r\nSo this method is used to those specific cases, to ensure how to map the error received to event source deal properly.\r\n\r\nIn the [AWS Api Gateway V2](/docs/main/adapters/aws/api-gateway-v2), we handle like this:\r\n\r\n```ts title=\"api-gateway-v2.adapter.ts\"\r\npublic onErrorWhileForwarding({\r\n  error,\r\n  delegatedResolver,\r\n  respondWithErrors,\r\n  event,\r\n  log,\r\n}: OnErrorProps<\r\n  APIGatewayProxyEventV2,\r\n  APIGatewayProxyStructuredResultV2\r\n>): void {\r\n  const body = respondWithErrors ? error.stack : '';\r\n  const errorResponse = this.getResponse({\r\n    event,\r\n    statusCode: 500,\r\n    body: body || '',\r\n    headers: {},\r\n    isBase64Encoded: false,\r\n    log,\r\n  });\r\n\r\n  delegatedResolver.succeed(errorResponse);\r\n}\r\n```\r\n\r\nIf the `respondWithErrors` flag is enabled, we will return the entire stack trail in the response, so the user will get a 500 error with enough information.\r\n\r\n:::important\r\n\r\nWhen implementing this method, you must call `delegatedResolver.succeed` or `delegedResolver.fail`, or your request will not be resolved.\r\n\r\n:::\r\n\r\nOther adapters may fail when an error occurs, the [AWS SQS](/docs/main/adapters/aws/sqs) adapter does that.\r\n\r\n```ts title=\"sqs.adapter.ts\"\r\npublic onErrorWhileForwarding({\r\n  error,\r\n  delegatedResolver,\r\n}: OnErrorProps<SQSEvent, IEmptyResponse>): void {\r\n  delegatedResolver.fail(error);\r\n}\r\n```\r\n\r\n## Well Done!\r\n\r\nNow you can create your own adapters to plug with any event source that you want.\r\n\r\n:::tip\r\n\r\nIf you get lost while building your adapter, see the source code of other adapters to get some ideas on how to implement your own adapter, you can see the code [here](https://github.com/H4ad/serverless-adapter/tree/main/src/adapters).\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/advanced/adapters/introduction.mdx",
    "content": "---\r\ntitle: Introduction\r\nposition: 1\r\n---\r\n\r\nAs we see in the [Architecture](../../architecture) section, adapters are responsible for handling the received event,\r\ntransforming the request in a way that your application can understand and then transforming the response in a way your cloud can understand.\r\n\r\nThe interface that represents an adapter is:\r\n\r\n```typescript\r\nexport interface AdapterContract<\r\n  TEvent,\r\n  TContext,\r\n  TResponse\r\n> {\r\n  getAdapterName(): string;\r\n  canHandle(\r\n    event: unknown,\r\n    context: TContext,\r\n    log: ILogger\r\n  ): boolean;\r\n  getRequest(\r\n    event: TEvent,\r\n    context: TContext,\r\n    log: ILogger\r\n  ): AdapterRequest;\r\n  getResponse(props: GetResponseAdapterProps<TEvent>): TResponse;\r\n  onErrorWhileForwarding(props: OnErrorProps<TEvent, TResponse>): void;\r\n}\r\n```\r\n\r\n> You can see in more details [in the API section](../../../api/Contracts/AdapterContract).\r\n\r\n## getAdapterName\r\n\r\nThis method just return the name of the Adapter, used by the library to log which adapter was resolved.\r\n\r\n## canHandle\r\n\r\nIn this method, you should implement the logic to detect if the event sent by the serverless environment should be handle by this adapter.\r\n\r\nYou must be very confident when you implement this method to not get conflict with another adapter.\r\n\r\n## getRequest\r\n\r\nIn this method, you should implement the logic to transform your event in an interface that the library could handle and forward to any framework.\r\n\r\nSo, you can use the constructor of your adapter to customize the options when create the request, or, just get the event info and then transform into a request.\r\n\r\nWhen I say that we create a request, I literally mean that I'm going to create a request for the framework, something like:\r\n\r\n- SQS: create a POST request to /sqs\r\n- SNS: create a POST request to /sns\r\n- and so on.\r\n\r\n## getResponse\r\n\r\nIn this method, you should map the response of the framework to a payload that serverless environment can handle.\r\n\r\nThe response is built based on what your framework returns in the request, something like:\r\n\r\nIf you return a json response based on the `{ success: true }` object, the response will contain the headers from that response and\r\nin the body will have the object you sent in text form and then you can map this body to whatever your event source needs as a response.\r\n\r\n## onErrorWhileForwarding\r\n\r\nWhen an error occurs while forwarding the request to the framework, this method is called,\r\ntherefore, you must implement what will be done when an error during the forwarding occurs.\r\n"
  },
  {
    "path": "www/docs/main/architecture.mdx",
    "content": "---\nsidebar_position: 2\n---\n\n# Architecture\n\nThe main purpose of this library is to allow the developer to add support for any cloud and as many event sources as he\nwants, without having to create an issue to request the feature or copy the library code because the library doesn't\nexpose good APIs for you to extend its functionality\n\nSo I refactored [@vendia/serverless-express](https://github.com/vendia/serverless-express) with 4 layers of abstraction:\nFramework, Handler, Resolver and Adapter.\n\n## Framework\n\nThe [FrameworkContract](https://github.com/H4ad/serverless-adapter/tree/main/src/contracts/framework.contract.ts) is responsible for forwarding\nto [IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage)\nand [ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse) for your application instance.\n\nWith this abstraction you can implement any framework you want, they just need to accept both parameters and\ncall [end](https://nodejs.org/api/http.html#class-httpserverresponse)\nin [ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse), so the library knows when to continue\nand return the response.\n\n## Handler\n\nThe [HandlerContract](https://github.com/H4ad/serverless-adapter/tree/main/src/contracts/handler.contract.ts) is responsible to get the input from the serverless and then\nmanage to call each layer of abstraction to return a response.\n\nWith this abstraction, you can implement different ways\nto receive input from your serverless environment.\n\nThey usually have the same structure, but if you need to deal with a\nvery different cloud, you can use this abstraction to add support for that cloud.\n\n:::tip\n\nHandler is a good choice for implementing (~~monsters~~) ways to receive input.\nFor example, we can create an http server as its handler to test our serverless code without having to launch the framework. Because? I don't know, but you can.\n\n:::\n\n## Resolver\n\nThe [ResolverContract](https://github.com/H4ad/serverless-adapter/tree/main/src/contracts/resolver.contract.ts) is responsible for waiting for the framework to handle the\nrequest and then returning the response to the cloud. Using AWS for example, you have three ways to wait for the\nresponse: returning a promise, calling the callback, and ~~using in-context methods~~, each option has its own benefits,\nbut generally the promise option will be the better because any good cloud provider will support promises.\n\n## Adapter\n\nFinally, the masterpiece of this library, the [AdapterContract](https://github.com/H4ad/serverless-adapter/tree/main/src/contracts/adapter.contract.ts) is responsible for\nhandling the received event, transforming the request in a way that your application can understand and then\ntransforming the response in a way your cloud can understand.\n\nWell, with these four contracts, you'll be able to add support to any cloud that exists (no more excuses not to use\ncloud X with NodeJS).\n"
  },
  {
    "path": "www/docs/main/frameworks/apollo-server.mdx",
    "content": "---\r\ntitle: Apollo Server\r\ndescription: See more about how to integrate with Apollo Server.\r\n---\r\n\r\nIn the following section, you will see how to integrate any cloud with your Apollo Server application.\r\n\r\n> We only support HTTP Requests, subscriptions is not supported yet.\r\n\r\n## Requirements\r\n\r\nFirst, you need to ensure you have the libs installed, so run this code:\r\n\r\n```bash\r\nnpm i --save @apollo/server\r\n```\r\n\r\nAlso, to be able to handle JSON requests, we can use [JsonBodyParserFramework](./helpers/body-parser), so let's install it:\r\n\r\n```bash\r\nnpm i --save body-parser http-errors\r\nnpm i --save-dev @types/body-parser\r\n```\r\n\r\n:::tip\r\n\r\nNeed to deal with CORS? See [CorsFramework](./helpers/cors) which helps you to add correct headers.\r\n\r\n:::\r\n\r\n## Usage\r\n\r\nThen, you just need to use the [ApolloServerFramework](/docs/api/Frameworks/ApolloServerFramework) when you create your adapter, like:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { CorsFramework } from '@h4ad/serverless-adapter/frameworks/cors';\r\nimport { ApolloServerFramework } from '@h4ad/serverless-adapter/frameworks/apollo-server';\r\nimport { JsonBodyParserFramework } from '@h4ad/serverless-adapter/frameworks/body-parser';\r\nimport { ApolloServer } from '@apollo/server';\r\n\r\nexport const app = new ApolloServer({\r\n  typeDefs: `type Query { message: String }`,\r\n  resolvers: {\r\n    Query: {\r\n      message: () => 'Hello World!',\r\n    }\r\n  },\r\n});\r\n\r\n// json-body is needed to handle JSON content type\r\nconst framework = new JsonBodyParserFramework(\r\n  new ApolloServerFramework(),\r\n);\r\n\r\n// you always need to start your application\r\napp.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests();\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setFramework(framework)\r\n  // continue to set the other options here.\r\n  // .setHandler(new DefaultHandler())\r\n  // .setResolver(new PromiseResolver())\r\n  // .addAdapter(new ApiGatewayV1Adapter())\r\n  // .addAdapter(new ApiGatewayV2Adapter())\r\n  // after adding all the necessary methods, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nNeed more examples? See more examples [here](https://github.com/H4ad/serverless-adapter-examples#apollo-server).\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nIs your application instance creation an asynchronous process? If so, you might want to consider using the [LazyFramework](./helpers/lazy), which can help with asynchronous startup.\r\n\r\n:::\r\n\r\n## Support for AWS SQS, SNS and others.\r\n\r\nWell, this framework will work great for adapters like [ApiGatewayV1Adapter](../adapters/aws/api-gateway-v1), [ApiGatewayV2Adapter](../adapters/aws/api-gateway-v2),\r\n[HttpTriggerV4Adapter](../adapters/azure/http-trigger-v4) and others based on pure HTTP requests.\r\n\r\nBut adapters like [SQSAdapter](../adapters/aws/sqs), [SNSAdapter](../adapters/aws/sns) and others by default cannot send a request with the correct format that\r\nApollo Server understands, it's not in your control how the request is constructed, the adapter that construct the request to Apollo.\r\n\r\nTo address this issue, i created the [ApolloServerMutationAdapter](/docs/api/Adapters/Apollo%20Server/ApolloServerMutationAdapter), an adapter for other adapters.\r\nIt follows the same principle of helper frameworks, it wraps the adapter you are using and customize the behavior to support sending valid requests to Apollo.\r\n\r\nLet's see how to integrate with AWS SQS and AWS SNS, first, let's create the schema.\r\n\r\n```ts\r\nconst schema = `\r\n  type Query { message: String }\r\n\r\n  type AWSResult {\r\n    result: String\r\n  }\r\n\r\n  type Mutation {\r\n    sqs (event: String): AWSResult\r\n    sns (event: String): AWSResult\r\n  }\r\n`;\r\n```\r\n\r\nIn this schema, you define a mutation with the name you want to give to AWS SQS, I just put `sqs` but you can put whatever you want.\r\n\r\nAbout the mutation parameters and the result, you `MUST` define the parameter as `event: String`, but you `CAN` change the `AWSResult` if you want.\r\nI explain further below about the decision to have this `event: String`.\r\n\r\nOk, after define the schema, let's create the apollo server instance.\r\n\r\n```ts\r\nimport { ApolloServer } from '@apollo/server';\r\nimport { GraphQLError } from 'graphql/error/GraphQLError';\r\nimport { DefaultServerlessApolloServerContext } from '@h4ad/serverless-adapter/frameworks/apollo-server';\r\nimport type { SNSEvent, SQSEvent } from 'aws-lambda';\r\n\r\nexport const app = new ApolloServer<DefaultServerlessApolloServerContext>({\r\n  typeDefs: schema,\r\n  resolvers: {\r\n    Query: {\r\n      message: () => 'Hello World!',\r\n    },\r\n    Mutation: {\r\n      sqs: (_, data, context) => {\r\n        // security measures: http://serverless-adapter.viniciusl.com.br/docs/main/adapters/aws/sqs#security\r\n        if (context.request.headers['host'] !== 'sqs.amazonaws.com')\r\n          throw new GraphQLError('Your host is not allowed to call this mutation.');\r\n\r\n        // here, you can manipulate the event data and do whatever you want with it.\r\n        const event = JSON.parse(data.event) as SQSEvent;\r\n\r\n        // I will just return the event data to better debugging\r\n        return ({\r\n          result: JSON.stringify(event),\r\n        });\r\n      },\r\n      sns: (_, data, context) => {\r\n        // security measures: http://serverless-adapter.viniciusl.com.br/docs/main/adapters/aws/sqs#security\r\n        if (context.request.headers['host'] !== 'sns.amazonaws.com')\r\n          throw new GraphQLError('Your host is not allowed to call this mutation.');\r\n\r\n        // here, you can manipulate the event data and do whatever you want with it.\r\n        const event = JSON.parse(data.event) as SNSEvent;\r\n\r\n        // I will just return the event data to better debugging\r\n        return ({\r\n          result: JSON.stringify(event),\r\n        });\r\n      },\r\n    },\r\n  },\r\n});\r\n```\r\n\r\nIn the code above, we created the Apollo Server Instance with the mutations that will handle the events from SQS and SNS.\r\n\r\nBecause of the nature of GraphQL, it is too hard to create strict schema definitions for each event source, so I just serialize in JSON the event and send it as string\r\ninside `data` with the type of `{ event: string }`.\r\n\r\nAbout the result of each mutation (`AWSResult`), you can customize it to return whatever you want, like the name, but you will need to specify the return inside `ApolloServerMutationAdapter`,\r\nwe will see this configuration in next section.\r\n\r\nWell, now we only need to expose the Apollo Server Instance using Serverless Adapter:\r\n\r\n```ts\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { ApolloServerMutationAdapter } from '@h4ad/serverless-adapter/adapters/apollo-server';\r\nimport { ApiGatewayV2Adapter, SNSAdapter, SQSAdapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport { PromiseResolver } from '@h4ad/serverless-adapter/resolvers/promise';\r\nimport { CorsFramework } from '@h4ad/serverless-adapter/frameworks/cors';\r\nimport { ApolloServerFramework, DefaultServerlessApolloServerContext } from '@h4ad/serverless-adapter/frameworks/apollo-server';\r\nimport { JsonBodyParserFramework } from '@h4ad/serverless-adapter/frameworks/body-parser';\r\n\r\nconst framework = new ApolloServerFramework<DefaultServerlessApolloServerContext>();\r\nconst jsonBodyFramework = new JsonBodyParserFramework(framework);\r\n\r\n// optional: you can configure cors using this guy here, if you don't want, just erase\r\nconst corsFramework = new CorsFramework(jsonBodyFramework, {\r\n  origin: '*',\r\n  maxAge: 30,\r\n});\r\n\r\n// needed to start the application, without this, the apollo server will throw an error\r\napp.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests();\r\n\r\n// let's add support for api gateway v2\r\nconst apiGatewayV2Adapter = new ApiGatewayV2Adapter();\r\n\r\n// let's add support for sqs\r\nconst sqsAdapter = new SQSAdapter();\r\nconst wrappedSqsAdapter = new ApolloServerMutationAdapter(\r\n  sqsAdapter,\r\n  {\r\n    mutationName: 'sqs', // remember the scheme? This is the name of the mutation\r\n    mutationResultQuery: '{ result }', // we specify the return as `AWSResult` and here we specify which properties we want to return of that type\r\n    // if we dont specify nothing, `{ __typename }` will be returned.\r\n  }\r\n);\r\n\r\n// let's add support for sns\r\nconst snsAdapter = new SNSAdapter();\r\nconst wrappedSnsAdapter = new ApolloServerMutationAdapter(\r\n  snsAdapter,\r\n  {\r\n    mutationName: 'sns', // remember the scheme? This is the name of the mutation\r\n    mutationResultQuery: '{ result }', // we specify the return as `AWSResult` and here we specify which properties we want to return of that type\r\n    // if we dont specify nothing, `{ __typename }` will be returned.\r\n  }\r\n);\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setFramework(corsFramework)\r\n  .setHandler(new DefaultHandler())\r\n  .setResolver(new PromiseResolver())\r\n  .addAdapter(apiGatewayV2Adapter)\r\n  .addAdapter(wrappedSqsAdapter)\r\n  .addAdapter(wrappedSnsAdapter)\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nNeed more examples? See more examples [here](https://github.com/H4ad/serverless-adapter-examples#apollo-server).\r\n\r\n:::\r\n\r\nThat's it! Now you are able to receive `API Gateway V2` requests and also integrate `AWS SQS` and `AWS SNS` into the same lambda function. Great, right?\r\n\r\n## Customizing the Context\r\n\r\nBy default, the context will be [DefaultServerlessApolloServerContext](/docs/api/Frameworks/ApolloServerFramework/DefaultServerlessApolloServerContext), but you can customize\r\nthe creation of the context by passing `context` variable inside `ApolloServerFramework`, like:\r\n\r\n```ts\r\nimport { ApolloServerFramework, DefaultServerlessApolloServerContext } from '@h4ad/serverless-adapter/frameworks/apollo-server';\r\n\r\n// I want the date when it's started, and also, i always recommend including the default context\r\ntype MyCustomContext = { startedAt: Date } & DefaultServerlessApolloServerContext;\r\n\r\nconst framework = new ApolloServerFramework<MyCustomContext>({\r\n  context: async ({ request, response }) => {\r\n    return {\r\n      startedAt: new Date(),\r\n      request,\r\n      response,\r\n    };\r\n  },\r\n});\r\n```\r\n"
  },
  {
    "path": "www/docs/main/frameworks/deepkit.mdx",
    "content": "---\r\ntitle: Deepkit\r\ndescription: See more about how to integrate with deepkit.\r\n---\r\n\r\n:::info\r\n\r\nThe following examples only work with deepkit over HTTP, you cannot use this framework to support websocket or rpc.\r\n\r\n:::\r\n\r\nFirst, you need to ensure you have the libs installed, so run this code:\r\n\r\n```bash\r\nnpm i --save @deepkit/app @deepkit/core @deepkit/framework @deepkit/http @deepkit/type @deepkit/type-compiler\r\n```\r\n\r\nThen, you need you just need to use the [HttpDeepkitFramework](../../api/Frameworks/HttpDeepkitFramework) when you create your adapter, like:\r\n\r\n```ts title=\"index.ts\"\r\nimport { App } from '@deepkit/app';\r\nimport { FrameworkModule } from '@deepkit/framework';\r\nimport { HtmlResponse, HttpKernel, HttpModule, HttpRouterRegistry } from '@deepkit/http';\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { HttpDeepkitFramework } from '@h4ad/serverless-adapter/frameworks/deepkit';\r\n\r\nconst app = new App({\r\n  controllers: [],\r\n  module: [\r\n    new HttpModule(),\r\n    new FrameworkModule()\r\n  ],\r\n});\r\n\r\nconst router = app.get(HttpRouterRegistry);\r\n\r\nrouter.get('/', () => {\r\n  return new HtmlResponse('<h1>Sample in Deepkit Project</h1>');\r\n});\r\n\r\nconst httpKernel = app.get(HttpKernel);\r\n\r\nexport const handler = ServerlessAdapter.new(httpKernel)\r\n  .setFramework(new HttpDeepkitFramework())\r\n  // .setHandler(new DefaultHandler())\r\n  // .setResolver(new PromiseResolver())\r\n  // .addAdapter(new AlbAdapter())\r\n  // .addAdapter(new SQSAdapter())\r\n  // .addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nNeed more examples? See more examples [here](https://github.com/H4ad/serverless-adapter-examples#deepkit).\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nIs your application instance creation asynchronous? Look the [LazyFramework](./helpers/lazy) which helps you in asynchronous startup.\r\n\r\n:::\r\n\r\n## About AWS\r\n\r\nI was only able to get Deepkit working when you deploy using NodeJS 16.x and using the `x86_64` architecture.\r\n\r\nAlso, I tried using the `serverless-offline` package and it throws an error about `could not find handler`, not sure why\r\nI changed the deployment configuration to upload code manually. So if you like to use `serverless framework`, know\r\nthat you will have problems trying to test locally.\r\n\r\n### FAQ\r\n\r\n### ERR_DLOPEN_FAILED\r\n\r\nError message: /var/task/node_modules/turbo-net/build/Release/turbo_net.node: cannot open shared object file: No such file or directory\r\nSolution: Change your lambda architecture to `x86_64`.\r\n\r\n### ENOENT\r\n\r\nError message: no such file or directory, mkdir 'var/debug/'\r\nSolution:\r\n\r\n```ts\r\n// change these options\r\nnew HttpModule({ debug: true }),\r\nnew FrameworkModule({ debug: true, httpLog: true }),\r\n// for\r\nnew HttpModule({ debug: false }),\r\nnew FrameworkModule({ debug: false, httpLog: false }),\r\n```\r\n\r\n:::tip\r\n\r\nNeed to deal with CORS? See [CorsFramework](./helpers/cors) which helps you to add correct headers.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/frameworks/express.mdx",
    "content": "---\r\ntitle: Express\r\ndescription: See more about how to integrate with Express.\r\n---\r\n\r\n> Supported versions: v4 and v5\r\n\r\nFirst, you need to ensure you have the libs installed, so run this code:\r\n\r\n```bash\r\nnpm i --save express\r\nnpm i --save-dev @types/express\r\n```\r\n\r\nThen, you need you just need to use the [ExpressFramework](../../api/Frameworks/ExpressFramework) when you create your adapter, like:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { ExpressFramework } from '@h4ad/serverless-adapter/frameworks/express';\r\n\r\nconst express = require('express');\r\n\r\nconst app = express();\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setFramework(new ExpressFramework())\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nIs your application instance creation asynchronous? Look the [LazyFramework](./helpers/lazy) which helps you in asynchronous startup.\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nNeed to deal with CORS? See [CorsFramework](./helpers/cors) which helps you to add correct headers.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/frameworks/fastify.mdx",
    "content": "---\r\ntitle: Fastify\r\ndescription: See more about how to integrate with Fastify.\r\n---\r\n\r\n> Supported versions: v4 and v5\r\n\r\nFirst, you need to ensure you have the libs installed, so run this code:\r\n\r\n```bash\r\nnpm i --save fastify\r\n```\r\n\r\nThen, you need you just need to use the [FastifyFramework](../../api/Frameworks/FastifyFramework) when you create your adapter, like:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { FastifyFramework } from '@h4ad/serverless-adapter/frameworks/fastify';\r\n\r\nconst Fastify = require('fastify');\r\n\r\nconst app = Fastify({ logger: true });\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setFramework(new FastifyFramework())\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nIs your application instance creation asynchronous? Look the [LazyFramework](./helpers/lazy) which helps you in asynchronous startup.\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nNeed to deal with CORS? See [CorsFramework](./helpers/cors) which helps you to add correct headers.\r\n\r\n:::\r\n\r\n"
  },
  {
    "path": "www/docs/main/frameworks/hapi.mdx",
    "content": "---\r\ntitle: Hapi\r\ndescription: See more about how to integrate with Hapi.\r\n---\r\n\r\nFirst, you need to ensure you have the libs installed, so run this code:\r\n\r\n```bash\r\nnpm i --save @hapi/hapi\r\nnpm i --save-dev @types/hapi\r\n```\r\n\r\nThen, you need you just need to use the [HapiFramework](../../api/Frameworks/HapiFramework) when you create your adapter, like:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { HapiFramework } from '@h4ad/serverless-adapter/frameworks/hapi';\r\n\r\nconst Hapi = require('@hapi/hapi');\r\n\r\nconst app = Hapi.server();\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setFramework(new HapiFramework())\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nIs your application instance creation asynchronous? Look the [LazyFramework](./helpers/lazy) which helps you in asynchronous startup.\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nNeed to deal with CORS? See [CorsFramework](./helpers/cors) which helps you to add correct headers.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/frameworks/helpers/body-parser.mdx",
    "content": "---\r\ntitle: Body Parser\r\ndescription: See more about how to deal with content type parsing in serverless.\r\n---\r\n\r\nThis framework is a helper framework that wraps around another framework and gets some options to configure content parsing in your app using the [body-parser](https://github.com/expressjs/body-parser) library behind the scenes.\r\n\r\n## Why?\r\n\r\nWhy should I use this framework instead of directly using my framework/application's `joe-doe-body-parser` package?\r\n\r\nFrameworks like `trpc`, `deepḱit` and other frameworks don't have a good way of dealing with content parsing, so with `BodyParserFramework` you can do the content parsing\r\nworks for these frameworks.\r\n\r\n## Requirements\r\n\r\nTo be able to use, first you need to install some packages:\r\n\r\n```bash\r\nnpm i --save body-parser http-errors\r\n```\r\n\r\nIf you are using TypeScript:\r\n\r\n```bash\r\nnpm i --save-dev @types/body-parser\r\n```\r\n\r\n## Usage\r\n\r\nLike [body-parser](https://github.com/expressjs/body-parser), you have four types of content that we support:\r\n\r\n- `application/json` using [JsonBodyParserFramework](/docs/api/Frameworks/BodyParserFramework/JsonBodyParserFramework).\r\n- `text/plain` using [TextBodyParserFramework](/docs/api/Frameworks/BodyParserFramework/TextBodyParserFramework).\r\n- `application/octet-stream` using [RawBodyParserFramework](/docs/api/Frameworks/BodyParserFramework/RawBodyParserFramework).\r\n- `application/x-www-form-urlencoded` using [UrlencodedBodyParserFramework](/docs/api/Frameworks/BodyParserFramework/UrlencodedBodyParserFramework).\r\n\r\n> If you have sent any other type of content using these body parsers, the body parser will skip parsing your content.\r\n\r\nThe first parameter is the instance of another framework, so if you want to use [Express](../express) for example and want to parse `application/json`, you can use like this:\r\n\r\n```ts\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { JsonBodyParserFramework, JsonBodyParserFrameworkOptions } from '@h4ad/serverless-adapter/frameworks/cors';\r\nimport { ExpressFramework } from '@h4ad/serverless-adapter/frameworks/express';\r\n\r\nconst express = require('express');\r\n\r\nconst expressFramework = new ExpressFramework();\r\n// see docs about the options in the original package:\r\n// https://github.com/expressjs/body-parser#bodyparserjsonoptions\r\nconst options: JsonBodyParserFrameworkOptions = { limit: 1024 * 1024 }; // limit body to 1mb\r\nconst framework = new JsonBodyParserFramework(expressFramework, options);\r\n\r\nexport const handler = ServerlessAdapter.new(express)\r\n  .setFramework(framework)\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\nIf you want to combine with more frameworks, just add others like:\r\n\r\n```ts\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { JsonBodyParserFramework, UrlencodedBodyParserFramework, RawBodyParserFramework } from '@h4ad/serverless-adapter/frameworks/body-parser';\r\nimport { CorsFramework } from '@h4ad/serverless-adapter/frameworks/cors';\r\nimport { ExpressFramework } from '@h4ad/serverless-adapter/frameworks/express'; import {  } from './cors.framework';\r\n\r\nconst expressFramework = new ExpressFramework();\r\n\r\n// combine as much as you want\r\nconst framework = new UrlencodedBodyParserFramework(\r\n  new RawBodyParserFramework(\r\n    new JsonBodyParserFramework(\r\n      expressFramework,\r\n      { limit: 1024 * 1024 }, // options\r\n    ),\r\n    { limit: 1024 * 1024 }, // options\r\n  ),\r\n  { limit: 1024 * 1024 }, // options\r\n);\r\n\r\n// you can also combine with cors\r\nconst finalFramework = new CorsFramework(framework);\r\n```\r\n\r\n:::tip\r\n\r\nIs your application instance creation asynchronous? Look the [LazyFramework](./lazy) which helps you in asynchronous startup.\r\n\r\n:::\r\n\r\n## Customizing\r\n\r\nIf you want to customize the error messages, like when the size limit is exceeded, you can use `customErrorHandler`, like this:\r\n\r\n```ts\r\nimport type { IncomingMessage, ServerResponse } from 'http';\r\nimport type { HttpError } from 'http-errors';\r\nimport { JsonBodyParserFramework, JsonBodyParserFrameworkOptions } from '@h4ad/serverless-adapter/frameworks/body-parser';\r\n\r\nconst options: JsonBodyParserFrameworkOptions = {\r\n  customErrorHandler: (req: IncomingMessage, response: ServerResponse, error: HttpError<any>) => {\r\n    response.setHeader('content-type', 'application/json');\r\n    response.statusCode = error.statusCode;\r\n    // always call end to return the error\r\n    response.end(JSON.stringify({\r\n      message: error.message,\r\n    }));\r\n  },\r\n};\r\nconst framework = new JsonBodyParserFramework(expressFramework, options);\r\n```\r\n"
  },
  {
    "path": "www/docs/main/frameworks/helpers/cors.mdx",
    "content": "---\r\ntitle: CORS\r\ndescription: See more about how to deal with CORS in serverless.\r\n---\r\n\r\nThis framework is a helper framework that wraps around another framework and gets some options to configure CORS in your app using the [cors](https://github.com/expressjs/cors) library behind the scenes.\r\n\r\n## Why?\r\n\r\nWhy should I use this framework instead of directly using my framework/application's `joe-doe-cors` package?\r\n\r\nUsing this framework, you can skip the `request` to your framework, so it's faster to handle it directly in the library instead of leaving it\r\nto your frame.\r\n\r\nAlso, frameworks like `trpc`, `deepḱit` and other frameworks don't have a good way of dealing with CORS, so with `CorsFramework` you can do the CORS\r\nworks for these frameworks.\r\n\r\nFinally, I added an optimization, inspired by [access control](https://github.com/primus/access-control/blob/master/index.js#L95-L115), which returns the Forbidden error when the origin is invalid\r\nor when the method is not allowed. In other packages, like `fastify/cors`, the `cors` itself used by this library and [even other languages](https://stackoverflow.com/questions/57212248/why-is-http-request-been-processed-in-action-even-when-cors-is-not-enabled),\r\nthey process the request if the origin is invalid and to me it sounds like a waste of resources, so we can just return the error to the user instead of processing the request which is sure to return the error in the user's browser.\r\n\r\n> If you want to disable this behaviour, set `{ forbiddenOnInvalidOriginOrMethod: false }` in the options.\r\n\r\n## Requirements\r\n\r\nTo be able to use, first you need to install some packages:\r\n\r\n```bash\r\nnpm i --save cors\r\n```\r\n\r\nIf you are using TypeScript:\r\n\r\n```bash\r\nnpm i --save-dev @types/cors\r\n```\r\n\r\n## Usage\r\n\r\nThe first parameter is the instance of another framework, so if you want to use [Express](../express) for example, you can just use like this:\r\n\r\n```ts\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { CorsFramework, CorsFrameworkOptions } from '@h4ad/serverless-adapter/frameworks/cors';\r\nimport { ExpressFramework } from '@h4ad/serverless-adapter/frameworks/express';\r\n\r\nconst express = require('express');\r\n\r\nconst expressFramework = new ExpressFramework();\r\n// see docs about the options in the original package:\r\n// https://github.com/expressjs/cors\r\nconst options: CorsFrameworkOptions = { origin: '*' };\r\nconst framework = new CorsFramework(expressFramework, options);\r\n\r\nexport const handler = ServerlessAdapter.new(express)\r\n  .setFramework(framework)\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nIs your application instance creation asynchronous? Look the [LazyFramework](./lazy) which helps you in asynchronous startup.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/frameworks/helpers/lazy.mdx",
    "content": "---\r\ntitle: Lazy\r\ndescription: See more about how to use Lazy Framework.\r\n---\r\n\r\nThis framework is a helper framework that wraps another framework and receives a function to asynchronously initialize the application.\r\n\r\nThe constructor looks like:\r\n\r\n```ts title=\"lazy.framework.ts\"\r\nconstructor(\r\n  protected readonly framework: FrameworkContract<TApp>,\r\n  protected readonly factory: () => Promise<TApp>,\r\n  protected readonly logger: ILogger = createDefaultLogger(),\r\n)\r\n```\r\n\r\nThe first parameter is the instance of another framework, so if you want to use [Express](../express) for example, you can just use like this:\r\n\r\n```ts\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { LazyFramework } from '@h4ad/serverless-adapter/frameworks/lazy';\r\nimport { ExpressFramework } from '@h4ad/serverless-adapter/frameworks/express';\r\n\r\nconst express = require('express');\r\n\r\nasync function bootstrap() {\r\n  const app = express();\r\n\r\n  // do the things asynchronously\r\n\r\n  return app;\r\n}\r\n\r\nconst expressFramework = new ExpressFramework();\r\nconst framework = new LazyFramework(expressFramework, bootstrap);\r\n\r\nexport const handler = ServerlessAdapter.new(null)\r\n  .setFramework(framework)\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n## Benefits\r\n\r\nThis is an optimized version that could save almost 1s (in my projects) because we initialize our app while the lambda warms up and before the lambda receives the first request.\r\n\r\n:::tip\r\n\r\nThe solution above is inspired by [top-level await](https://aws.amazon.com/pt/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda/), it is very much worth reading.\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nNeed to deal with CORS? See [CorsFramework](./cors) which helps you to add correct headers.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/frameworks/koa.mdx",
    "content": "---\r\ntitle: Koa\r\ndescription: See more about how to integrate with Koa.\r\n---\r\n\r\nFirst, you need to ensure you have the libs installed, so run this code:\r\n\r\n```bash\r\nnpm i --save koa\r\nnpm i --save-dev @types/koa\r\n```\r\n\r\nThen, you need you just need to use the [KoaFramework](../../api/Frameworks/KoaFramework) when you create your adapter, like:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { KoaFramework } from '@h4ad/serverless-adapter/frameworks/koa';\r\n\r\nconst Koa = require('koa');\r\n\r\nconst app = new Koa();\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setFramework(new KoaFramework())\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nIs your application instance creation asynchronous? Look the [LazyFramework](./helpers/lazy) which helps you in asynchronous startup.\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nNeed to deal with CORS? See [CorsFramework](./helpers/cors) which helps you to add correct headers.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/frameworks/nestjs.mdx",
    "content": "---\r\ntitle: NestJS\r\ndescription: See more about how to integrate with NestJS.\r\n---\r\n\r\n\r\n\r\n\r\nimport BrowserWindow from '@site/src/components/BrowserWindow';\r\nimport TabItem from '@theme/TabItem';\r\nimport Tabs from '@theme/Tabs';\r\n\r\nAccords NestJS docs:\r\n\r\n<BrowserWindow url=\"https://docs.nestjs.com/first-steps#platform\">\r\n\r\nThere are two HTTP platforms supported out-of-the-box: `express` and `fastify`. You can choose the one that best suits your needs.\r\n\r\n- platform-express: `Express` is a well-known minimalist web framework for node. It's a battle tested, production-ready library with lots of resources implemented by the community. The `@nestjs/platform-express` package is used by default. Many users are well served with Express, and need take no action to enable it.\r\n- platform-fastify: `Fastify` is a high performance and low overhead framework highly focused on providing maximum efficiency and speed. Read how to use it here.\r\n\r\nThe NestJS is platform-agnostic, so we can choose which platform we will use. By default, I always use express but if in your company you use fastify, it's okay too.\r\n\r\n</BrowserWindow>\r\n\r\nSo, to add support to NestJS, we have two ways:\r\n\r\n<Tabs groupId=\"framework-nestjs\">\r\n\r\n<TabItem value=\"nestjs-express\" label=\"Express\" default>\r\n\r\n```typescript title=\"index.ts\"\r\nimport { NestFactory } from '@nestjs/core';\r\nimport { ExpressAdapter } from '@nestjs/platform-express';\r\nimport { LazyFramework } from '@h4ad/serverless-adapter/frameworks/lazy';\r\nimport { ExpressFramework } from '@h4ad/serverless-adapter/frameworks/express';\r\nimport { AppModule } from './app.module';\r\n\r\nasync function bootstrap() {\r\n  const nestApp = await NestFactory.create(AppModule, new ExpressAdapter());\r\n\r\n  // we need to wait until it initializes\r\n  await nestApp.init();\r\n\r\n  // then we get the instance of http adapter, it will be express\r\n  const app = nestApp.getHttpAdapter().getInstance();\r\n\r\n  return app;\r\n}\r\n\r\nconst expressFramework = new ExpressFramework();\r\n// the initialization of nestjs is asynchronous, so you can use the lazy framework.\r\nconst framework = new LazyFramework(expressFramework, bootstrap);\r\n\r\nexport const handler = ServerlessAdapter.new(null)\r\n  .setFramework(framework)\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n</TabItem>\r\n\r\n<TabItem value=\"nestjs-fastify\" label=\"Fastify\" default>\r\n\r\n```typescript title=\"index.ts\"\r\nimport { NestFactory } from '@nestjs/core';\r\nimport { FastifyAdapter } from '@nestjs/platform-fastify';\r\nimport { LazyFramework } from '@h4ad/serverless-adapter/frameworks/lazy';\r\nimport { FastifyFramework } from '@h4ad/serverless-adapter/frameworks/fastify';\r\nimport { AppModule } from './app.module';\r\n\r\nasync function bootstrap() {\r\n  const nestApp = await NestFactory.create(AppModule, new FastifyAdapter());\r\n\r\n  // we need to wait until it initializes\r\n  await nestApp.init();\r\n\r\n  // then we get the instance of http adapter, it will be fastify\r\n  const app = nestApp.getHttpAdapter().getInstance();\r\n\r\n  return app;\r\n}\r\n\r\nconst fastifyFramework = new FastifyFramework();\r\n// the initialization of nestjs is asynchronous, so you can use the lazy framework.\r\nconst framework = new LazyFramework(fastifyFramework, bootstrap);\r\n\r\nexport const handler = ServerlessAdapter.new(null)\r\n  .setFramework(framework)\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n</TabItem>\r\n\r\n</Tabs>\r\n\r\n:::tip\r\n\r\nNeed to deal with CORS? See [CorsFramework](./helpers/cors) which helps you to add correct headers.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/frameworks/polka.mdx",
    "content": "---\r\ntitle: Polka\r\ndescription: See more about how to integrate with Polka.\r\n---\r\n\r\nFirst, you need to ensure you have the libs installed, so run this code:\r\n\r\n```bash\r\nnpm i --save polka\r\nnpm i --save-dev @types/polka\r\n```\r\n\r\nThen, you need you just need to use the [PolkaFramework](../../api/Frameworks/PolkaFramework) when you create your adapter, like:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { PolkaFramework } from '@h4ad/serverless-adapter/frameworks/polka';\r\n\r\nconst Polka = require('Polka');\r\n\r\nconst app = Polka();\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setFramework(new PolkaFramework())\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nIs your application instance creation asynchronous? Look the [LazyFramework](./helpers/lazy) which helps you in asynchronous startup.\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nNeed to deal with CORS? See [CorsFramework](./helpers/cors) which helps you to add correct headers.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/frameworks/trpc.mdx",
    "content": "---\r\ntitle: tRPC\r\ndescription: See more about how to integrate with tRPC.\r\n---\r\n\r\n:::info\r\n\r\nThe following examples only work with tRPC over HTTP, you cannot use this framework to support websocket or subscriptions.\r\n\r\n:::\r\n\r\nFirst, you need to ensure you have the libs installed, so run this code:\r\n\r\n```bash\r\nnpm i --save @trpc/server body-parser\r\n```\r\n\r\n> `body-parser` is needed to parse the body of the request to JSON.\r\n\r\nThen, you just need to use the [TrpcFramework](../../api/Frameworks/TrpcFramework) when you create your adapter, like:\r\n\r\n```ts title=\"index.ts\"\r\nimport * as trpc from '@trpc/server';\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { TrpcFramework, TrpcAdapterContext, TrpcFrameworkOptions } from '@h4ad/serverless-adapter/frameworks/trpc';\r\nimport { JsonBodyParserFramework } from '@h4ad/serverless-adapter/frameworks/body-parser';\r\nimport { CorsFramework } from '@h4ad/serverless-adapter/frameworks/cors';\r\nimport { z } from 'zod';\r\n\r\ntype CustomContext = { currentDate: Date };\r\ntype TrpcContext = TrpcAdapterContext<CustomContext>;\r\n\r\nconst t = trpc.initTRPC.context<TrpcContext>().create();\r\nconst appRouter = t.router({\r\n  getUser: t.procedure.input(z.string()).query((req) => {\r\n    req.input; // string\r\n    return { id: req.input, name: 'Bilbo' };\r\n  }),\r\n  createUser: t.procedure\r\n    // validate input with Zod\r\n    .input(z.object({ name: z.string().min(5) }))\r\n    .mutation(({ input }) => {\r\n      return {\r\n        created: true,\r\n        newName: input.name,\r\n      };\r\n    })\r\n});\r\n\r\nconst frameworkOptions: TrpcFrameworkOptions<CustomContext> = {\r\n  createContext: () => ({ currentDate: new Date() }),\r\n};\r\n\r\nconst framework = new TrpcFramework<TrpcContext>(frameworkOptions);\r\nconst jsonFramework = new JsonBodyParserFramework(framework);\r\nconst corsFramework = new CorsFramework(jsonFramework); // see more about: https://serverless-adapter.viniciusl.com.br/docs/main/frameworks/cors\r\n\r\nexport const handler = ServerlessAdapter.new(appRouter)\r\n  .setFramework(corsFramework)\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nNeed more examples? See more examples [here](https://github.com/H4ad/serverless-adapter-examples#trpc).\r\n\r\n:::\r\n\r\n## Integrating with Adapters\r\n\r\nThis framework is a little special when dealing with request URLs because of the structure of tRPC.\r\n\r\nSo when you integrate with an adapter like [SQSAdapter](/docs/main/adapters/aws/sqs), when you receive an event, the adapter will forward the request to `/sqs` by default\r\nbut because of the structure of tRPC, the framework will change the request URL to just `sqs`.\r\n\r\nWith this behavior, to integrate with [SQSAdapter](/docs/main/adapters/aws/sqs), you will create the following mutation:\r\n\r\n```typescript title=\"index.ts\"\r\nimport type { SQSEvent } from 'aws-lambda';\r\nimport * as trpc from '@trpc/server';\r\nimport { TrpcAdapterContext } from '@h4ad/serverless-adapter/frameworks/trpc';\r\nimport { z } from 'zod';\r\n\r\ntype TrpcContext = TrpcAdapterContext<unknown>;\r\n\r\nconst t = trpc.initTRPC.context<TrpcContext>().create();\r\n\r\nconst appRouter = t.router({\r\n  sqs: t.procedure\r\n    .input(z.object({Records: z.array(z.any())}))\r\n    .mutation(({ctx, input}) => {\r\n      if (ctx.getHeader('host') !== 'sqs.amazonaws.com')\r\n        throw new TRPCError({\r\n          code: 'UNAUTHORIZED',\r\n          message: 'Wrong host.',\r\n        });\r\n\r\n      const event = input as SQSEvent;\r\n\r\n      // Do whatever you want\r\n      // and you dont need to return nothing\r\n    }),\r\n});\r\n```\r\n\r\n:::warning About another adapters\r\n\r\nNever forget to check the host header as you could introduce a security hole when adding support for AWS Api Gateway and other adapters.\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nYou can see a working example [here](https://github.com/H4ad/serverless-adapter-examples/tree/master/src/trpc/aws/api-gateway-v2-and-sqs.entry.ts).\r\n\r\n:::\r\n\r\n## Default Context and Custom context\r\n\r\nBy default, we provide you with a few methods to get information from the request and modify the response,\r\nto learn more, take a look at [TrpcAdapterBaseContext](../../api/Frameworks/TrpcFramework/TrpcAdapterBaseContext).\r\n\r\nAlso, you can pass new properties to the context by setting the `createContext` function inside the options,\r\nlike the code below:\r\n\r\n```typescript title=\"index.ts\"\r\nimport * as trpc from '@trpc/server';\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { TrpcFramework, TrpcAdapterContext, TrpcFrameworkOptions } from '@h4ad/serverless-adapter/frameworks/trpc';\r\nimport { JsonBodyParserFramework } from '@h4ad/serverless-adapter/frameworks/body-parser';\r\nimport { CorsFramework } from '@h4ad/serverless-adapter/frameworks/cors';\r\n\r\ntype CustomContext = { potato: boolean };\r\ntype TrpcContext = TrpcAdapterContext<CustomContext>;\r\n\r\nconst t = trpc.initTRPC.context<TrpcContext>().create();\r\nconst appRouter = t.router({\r\n  add: t.procedure\r\n    .mutation(({ ctx }) => {\r\n      // get the request url\r\n      const requestUrl = ctx.getUrl();\r\n\r\n      // this will change the status code of the request to 204.\r\n      ctx.setStatus(204);\r\n    }),\r\n});\r\n\r\nconst frameworkOptions: TrpcFrameworkOptions<TrpcContext> = {\r\n  // you can return a promise\r\n  createContext: () => Promise.resolve({ potato: true }),\r\n  // createContext: () => ({ potato: false }),\r\n};\r\n\r\nconst framework = new TrpcFramework<TrpcContext>(frameworkOptions);\r\nconst jsonFramework = new JsonBodyParserFramework(framework);\r\nconst corsFramework = new CorsFramework(jsonFramework); // see more about: https://serverless-adapter.viniciusl.com.br/docs/main/frameworks/cors\r\n\r\nexport const handler = ServerlessAdapter.new(appRouter)\r\n  .setFramework(corsFramework)\r\n  // continue to set the other options here.\r\n  //.setHandler(new DefaultHandler())\r\n  //.setResolver(new PromiseResolver())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nIs your application instance creation asynchronous? Look the [LazyFramework](./helpers/lazy) which helps you in asynchronous startup.\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nNeed to deal with CORS? See [CorsFramework](./helpers/cors) which helps you to add correct headers.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/getting-started/customizing.mdx",
    "content": "---\r\ntitle: Customizing\r\nposition: 2\r\ndescription: See more about how to customize this library.\r\n---\r\n\r\nWith the instance of adapter, we have some options:\r\n\r\n### setHandler\r\n\r\n> Calling this method more than once throws an error.\r\n\r\nDefines the handler that will get the event, context and callback and pass it to the adapter and framework.\r\n\r\n:::tip\r\n\r\nSee supported handlers in [Handlers Section](/docs/main/handlers/default))\r\n\r\n:::\r\n\r\n### setResolver\r\n\r\n> Calling this method more than once throws an error.\r\n\r\nDefines the resolver that aims to resolve the response to serverless and stop its execution when the request ends.\r\n\r\n:::tip\r\n\r\nSee supported resolvers in [Resolvers Section](/docs/main/resolvers/promise))\r\n\r\n:::\r\n\r\n### setFramework\r\n\r\n> Calling this method more than once throws an error.\r\n\r\nDefines the framework that will process requests.\r\n\r\n:::tip\r\n\r\nSee supported frameworks in [Frameworks Section](/docs/main/frameworks/nestjs))\r\n\r\n:::\r\n\r\n### setLogger\r\n\r\nDefines the logger service used during the execution of the handler\r\n\r\n:::tip\r\n\r\nTo know how to implement, see the [Logger Interface](../../api/Core/Logger/ILogger) in API section.\r\n\r\n:::\r\n\r\n### setBinarySettings\r\n\r\nDefines the binary settings for whether the response should be treated as binary or not.\r\n\r\nWhen you call this method, you need to pass the interface [BinarySettings](../../api/Types/BinarySettings), and you have two options:\r\n\r\n- Send an function called `isBinary` to verify looking inside the headers if the response should be treated as binary.\r\n- Or send the specific `contentTypes` and `contentEncodings` that should be treated as binary.\r\n\r\nAfter that, your adapter needs to handle the binary data, it will deal correctly because they know which responses are encoded in binary.\r\n\r\nNot every adapter deals with binary but if you used adapters like [ApiGatewayV1](../adapters/aws/api-gateway-v1) or [ApiGatewayV2](../adapters/aws/api-gateway-v2),\r\nyou should be aware of this configuration.\r\n\r\nBy default, the library already handles some common cases like [DEFAULT_BINARY_CONTENT_TYPES](../../api/Core/Constants/DEFAULT_BINARY_CONTENT_TYPES) for `contentTypes`\r\nand [DEFAULT_BINARY_ENCODINGS](../../api/Core/Constants/DEFAULT_BINARY_ENCODINGS) for `contentEncodings`.\r\n\r\n## setRespondWithErrors\r\n\r\nDefines the `responseWithErrors`, a property that indicates whether the error stack should be included in the response or not\r\n\r\nThe errors this option will usually handle are errors during forwarding to your framework, eg: when your framework throws error 500 from a middleware error.\r\n\r\nBy default, this option will be `true` only when the `NODE_ENV` is equal to `development`.\r\n\r\n## addAdapter\r\n\r\nAdd an adapter to the adapters list to handle the event coming from any serverless event source.\r\n\r\nYou can call this method multiple times to add support for whatever event source you want.\r\n\r\n:::tip\r\n\r\nTo know which adapters you can use, see the [Adapters](/docs/main/adapters/introduction)) section.\r\n\r\n:::\r\n\r\n\r\n"
  },
  {
    "path": "www/docs/main/getting-started/examples.mdx",
    "content": "---\r\ntitle: Examples\r\nposition: 4\r\ndescription: See more about examples of how to use this library.\r\n---\r\n\r\nYou can see some examples of how to use this library [here](https://github.com/H4ad/serverless-adapter-examples).\r\n"
  },
  {
    "path": "www/docs/main/getting-started/installation.mdx",
    "content": "---\r\ntitle: Installation\r\nposition: 1\r\ndescription: See more about how to install this library.\r\n---\r\n\r\nimport TabItem from '@theme/TabItem';\r\nimport Tabs from '@theme/Tabs';\r\n\r\nThe <a href=\"https://www.npmjs.com/package/@h4ad/serverless-adapter\">Serverless Adapter package</a> has everything you need to start.\r\n\r\n## Requirements\r\n\r\nCurrent versions supported by this library are 18.x and 20.x.\r\n\r\n## Installing\r\n\r\nFirst, inside your project, run the following command:\r\n\r\n<Tabs>\r\n<TabItem value=\"npm\" label=\"NPM\" default>\r\n\r\n```bash\r\n  npm i --save @h4ad/serverless-adapter\r\n```\r\n\r\n</TabItem>\r\n\r\n<TabItem value=\"yarn\" label=\"Yarn\">\r\n\r\n```bash\r\nyarn add @h4ad/serverless-adapter\r\n```\r\n\r\n</TabItem>\r\n</Tabs>\r\n"
  },
  {
    "path": "www/docs/main/getting-started/usage.mdx",
    "content": "---\r\ntitle: Usage\r\nposition: 2\r\ndescription: See more about how to use this library.\r\n---\r\n\r\nTo start to use, first you need to know what you need to import, let's start showing the [ServerlessAdapter](/docs/api/ServerlessAdapter).\r\n\r\n```tsx\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\n```\r\n\r\nWe need to pass to [Serverless Adapter](/docs/api/ServerlessAdapter) the instance of your api, let's look an example with:\r\n\r\n- Framework: [Express](../frameworks/express).\r\n- Adapters: [AWS Api Gateway V2 Adapter](../adapters/aws/api-gateway-v2).\r\n- Handler: [Default Handler](../handlers/aws).\r\n- Resolver: [Promise Resolver](../resolvers/promise).\r\n\r\n:::warning\r\nIf you are using `Typescript`, imports will only work exactly as in the example\r\nif you set your `moduleResolution` to `nodenext` or `bundler` in your `tsconfig.json`.\r\n\r\nIf you don't want to change this, you should append `/lib` after the package name,\r\nlike `@h4ad/serverless-adapter/lib/frameworks/express/index`.\r\n:::\r\n\r\n```ts\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { ExpressFramework } from '@h4ad/serverless-adapter/frameworks/express';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport { PromiseResolver } from '@h4ad/serverless-adapter/resolvers/promise';\r\nimport { ApiGatewayV2Adapter } from '@h4ad/serverless-adapter/adapters/aws';\r\n\r\nconst express = require('express');\r\n\r\nconst app = express();\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setFramework(new ExpressFramework())\r\n  .setHandler(new DefaultHandler())\r\n  .setResolver(new PromiseResolver())\r\n  .addAdapter(new ApiGatewayV2Adapter())\r\n  // if you need more adapters\r\n  // just append more `addAdapter` calls\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nTo know more about the frameworks that you can use, see [Frameworks Section](../../category/frameworks).\r\n\r\n:::\r\n\r\n:::tip\r\n\r\nTo know more about the handlers that you can use, see [Handlers Section](../../category/handlers).\r\n\r\n:::\r\n\r\n\r\n:::tip\r\n\r\nTo know more about the resolvers that you can use, see [Resolvers Section](../../category/resolvers).\r\n\r\n:::\r\n\r\n\r\n:::tip\r\n\r\nTo know more about the adapters that you can use, see [Adapters Section](../../category/adapters).\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/handlers/aws.mdx",
    "content": "---\r\ntitle: AWS\r\ndescription: See more about how to integrate with AWS Lambda.\r\n---\r\n\r\n:::tip\r\n\r\nDon't know what a handler is? See the [Architecture](../architecture#handler) section.\r\n\r\n:::\r\n\r\nThis is a serverless handler implementation that will return a function that expect to receive the following arguments: event, context and callback, respectively.\r\n\r\n```js\r\nfunction(event, context, callback) {...}\r\n```\r\n\r\nIf your cloud's serverless handler signature is the same, you can use this handler.\r\n\r\nThis is usually enough to add support for clouds like: AWS, Huawei and others.\r\n\r\n## Usage\r\n\r\nTo use, you can import and call the method [setHandler](../../api/ServerlessAdapter#method-sethandler), as per the code below:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new DefaultHandler())\r\n  // continue to set the other options here.\r\n  //.setResolver(new PromiseResolver())\r\n  //.setFramework(new ExpressFramework())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n## AWS Lambda Response Streaming\r\n\r\n:::info\r\n\r\nThis handler is intended to be used when you integrate with `FunctionURLs`, which is the only service that supports streaming on AWS currently,\r\n[read more](https://aws.amazon.com/blogs/compute/introducing-aws-lambda-response-streaming/).\r\n\r\n:::\r\n\r\nBy default, every Lambda will be `BUFFERED`, which means we need to wait for the framework to write all the content of the response until we send it to the user.\r\n\r\nBut when you enable the `RESPONSE_STREAM` mode within your Lambda settings, the framework will send the response to the user as fast as possible, without waiting for the framework to write all the content.\r\n\r\nTo support this behavior, we need to change three things:\r\n\r\n- Instead of `DefaultHandler`, you should use [AwsStreamHandler](../../api/handlers/AwsStreamHandler).\r\n- Instead of `PromiseResolver` or whatever, you should use [DummyResolver](../../api/resolvers/DummyResolver).\r\n  - Resolvers are not used in this mode, so you can just use this dummy version.\r\n- Add the adapter [ApiGatewayV2Adapter](../../api/adapters/aws/ApiGatewayV2Adapter).\r\n  - It is required to handle function URLs, but you can add more if you wish.\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { AwsStreamHandler } from '@h4ad/serverless-adapter/handlers/aws';\r\nimport { DummyResolver } from '@h4ad/serverless-adapter/resolvers/dummy';\r\nimport { ApiGatewayV2Adapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new AwsStreamHandler())\r\n  .setResolver(new DummyResolver())\r\n  .setAdapter(new ApiGatewayV2Adapter())\r\n  // continue to set the other options here.\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  //.setFramework(new ExpressFramework())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\nAs you see, we only have to change the `setHandler`, `setResolver` and `setAdapter` methods, that's all!\r\n\r\n### My execution is taking too long\r\n\r\nWell, maybe is caused because your event loop is not empty when the request finishes, in this case, you can set `callbackWaitsForEmptyEventLoop=false` on [AwsStreamHandler](../../api/handlers/AwsStreamHandler).\r\n\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { AwsStreamHandler } from '@h4ad/serverless-adapter/handlers/aws';\r\nimport { DummyResolver } from '@h4ad/serverless-adapter/resolvers/dummy';\r\nimport { ApiGatewayV2Adapter } from '@h4ad/serverless-adapter/adapters/aws';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setHandler(new AwsStreamHandler({ callbackWaitsForEmptyEventLoop: false }))\r\n  .setResolver(new DummyResolver())\r\n  .setAdapter(new ApiGatewayV2Adapter())\r\n  // continue to set the other options here.\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  //.setFramework(new ExpressFramework())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n### Can I use SQS and other services?\r\n\r\nWell, I don't know, but you can try. At least with `SQS` I was able to get the messages, but I couldn't use the `partial batch response` feature.\r\n\r\nOther services may or may not work, at least if it's a service that doesn't need a response, maybe it works now.\r\n\r\n## Examples\r\n\r\nYou can see examples of how to use [here](https://github.com/H4ad/serverless-adapter-examples).\r\n"
  },
  {
    "path": "www/docs/main/handlers/azure.mdx",
    "content": "---\r\ntitle: Azure\r\ndescription: See more about how to integrate with Azure Function.\r\n---\r\n\r\n:::tip\r\n\r\nDon't know what a handler is? See the [Architecture](../architecture#handler) section.\r\n\r\n:::\r\n\r\nThis is a implementation that will return a function that expect to receive the following arguments: context and event, respectively.\r\n\r\n```js\r\nfunction(context, event) {...}\r\n```\r\n\r\n## Requirements\r\n\r\nFirst, install the types for this adapter:\r\n\r\n```bash\r\nnpm i --save-dev @azure/functions@3.x\r\n```\r\n\r\n## Customize\r\n\r\nBy default we use [log property](https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=v2-v3-v4-export%2Cv2-v3-v4-done%2Cv2%2Cv2-log-custom-telemetry%2Cv2-accessing-request-and-response%2Cwindows-setting-the-node-version#contextlog-method) inside `Context` as default logger for this library .\r\n\r\nWe detect when the log instance is created with [createDefaultLogger](../../api/Core/Logger/createDefaultLogger) and then\r\nreplace this instance with the instance inside `Context`.\r\n\r\nIf you want to log using the original instance [createDefaultLogger](../../api/Core/Logger/createDefaultLogger),\r\nyou can set the `useContextLogWhenInternalLogger` option to `false` for [AzureHandlerOptions](../../api/Handlers/AzureHandler/AzureHandlerOptions).\r\n\r\n```typescript\r\nimport { AzureHandler } from '@h4ad/serverless-adapter/handlers/azure';\r\n\r\nconst handler = new AzureHandler({\r\n  useContextLogWhenInternalLogger: false,\r\n});\r\n```\r\n\r\n## Usage\r\n\r\nFirst, you need to configure your `function.json` to be able to receive all requests from Azure.\r\n\r\n```json title=\"function.json\"\r\n{\r\n  \"bindings\": [\r\n    {\r\n      \"authLevel\": \"anonymous\",\r\n      \"type\": \"httpTrigger\",\r\n      \"direction\": \"in\",\r\n      \"name\": \"req\",\r\n      \"route\": \"{*segments}\"\r\n    },\r\n    {\r\n      \"type\": \"http\",\r\n      \"direction\": \"out\",\r\n      \"name\": \"$return\"\r\n    }\r\n  ]\r\n}\r\n```\r\n\r\nThen, you can import and call the method [setHandler](../../api/ServerlessAdapter#method-sethandler), as per the code below:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { AzureHandler } from '@h4ad/serverless-adapter/handlers/azure';\r\nimport { PromiseResolver } from '@h4ad/serverless-adapter/resolvers/promise';\r\nimport { HttpTriggerV4Adapter } from '@h4ad/serverless-adapter/adapters/azure';\r\nimport app from './app';\r\n\r\nexport default ServerlessAdapter.new(app)\r\n  .setHandler(new AzureHandler())\r\n  .setResolver(new PromiseResolver())\r\n  // continue to set the other options here.\r\n  // .setFramework(new ExpressFramework())\r\n  .addAdapter(new HttpTriggerV4Adapter())\r\n  .build();\r\n```\r\n\r\n:::caution\r\n\r\nBe careful when exporting the handler because in azure you must `export default` and in [DefaultHandler](./aws)\r\nyou must `export const handler`.\r\n\r\n:::\r\n\r\nThe above code will add support for Azure Http Trigger V4, to learn more about Http Trigger, see the [adapter docs](../adapters/azure/http-trigger-v4).\r\n\r\n:::caution Attention\r\n\r\nYou `MUST` use [PromiseResolver](../resolvers/promise) to integrate with `AzureHandler`, other resolvers didn't work with Azure.\r\n\r\n:::\r\n\r\n## Examples\r\n\r\nYou can see examples of how to use [here](https://github.com/H4ad/serverless-adapter-examples).\r\n"
  },
  {
    "path": "www/docs/main/handlers/digital-ocean.mdx",
    "content": "---\ntitle: Digital Ocean\ndescription: See more about how to integrate with DigitalOcean Functions.\n---\n\n:::tip\n\nDon't know what a handler is? See the [Architecture](../architecture#handler) section.\n\n:::\n\n## Requirements\n\nWhen you work with DigitalOcean Functions, in the root of your repository you will have a file called `project.yml` which is used\nto determine the structure of your functions and will be used to deploy your code to DigitalOcean.\n\nTo this library understand the requests coming from DigitalOcean, you need to modify the default code of `project.yml`:\n\n```diff\npackages:\n  - name: [name-of-your-api]\n    functions:\n      - name: 'prod'\n        main: ''\n        runtime: 'nodejs:18'\n-        web: true\n+        web: 'raw'\n```\n\nAlso, you will need `doctl`, the DigitalOcean CLI, see [how to install](https://docs.digitalocean.com/reference/doctl/how-to/install/) before proceeding.\n\n## Usage\n\nImport and call the method [setHandler](../../api/ServerlessAdapter#method-sethandler), as per the code below:\n\n```ts title=\"index.ts\"\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\nimport { DigitalOceanHandler } from '@h4ad/serverless-adapter/handlers/digital-ocean';\nimport { PromiseResolver } from '@h4ad/serverless-adapter/resolvers/promise';\nimport { HttpFunctionAdapter } from '@h4ad/serverless-adapter/adapters/digital-ocean';\nimport app from './app';\n\nexport const main = ServerlessAdapter.new(app)\n  .setHandler(new DigitalOceanHandler())\n  .setResolver(new PromiseResolver())\n  // continue to set the other options here.\n  // .setFramework(new ExpressFramework())\n  .addAdapter(new HttpFunctionAdapter())\n  .build();\n```\n\n:::caution\n\nBe careful when exporting the handler because in DigitalOcean you must `export const main`.\n\n:::\n\n## Integrating with Existing API\n\n:::info\n\nThis configuration is meant to be used for one API/function only, if you want to have multiple APIs and functions inside\nin the same repository, you can skip this section.\n\n:::\n\nSo, let's assume you're a good developer and like to follow best practices, and your api's folder structure looks like this:\n\n- package.json\n- package-lock.json\n- tsconfig.json\n- src\n  - index.ts\n\nThe first thing we need to do is create the `packages` folder and the `function` folder for the DigitalOcean:\n\n- packages\n  - `[name-of-your-package]`\n    - api\n\nChange `[name-of-your-package]` to your project name, like: `joe-book-store`. In the final, DigitalOcean will create a DNS as\n`https://faas-nyc1-<id>.doserverless.co/api/v1/web/<namespace>/joe-book-store/api`.\n\nOkay, with the folders created, let's create a file called `.include` inside the `api` folder with the following content:\n\n```text title=\".include\"\ndeploy.zip\n```\n\nBy default, `doctl` which is DigitalOcean CLI already packs your code inside `packages/[your-package-name]/api`, but I want to have a better configuration and use my own library,\n[node-modules-packer](https://github.com/H4ad/node-modules-packer) which packs all the code faster than running `doctl` and also can minify your code.\n\nOkay, after configure `.include`, let's modify your `project.yml` to be able to deploy your API:\n\n```diff title=\"project.yml\"\npackages:\n  - name: [name-of-your-package]\n    functions:\n      - name: 'api'\n-       main: ''\n+       main: 'dist/index.main' # if you put the code of ServerlessAdapter in different file, you should change here.\n        runtime: 'nodejs:18'\n-       web: true\n+       web: 'raw'\n```\n\nFinally, let's now add some scripts to be able to deploy our code using [node-modules-packer](https://github.com/H4ad/node-modules-packer), inside `package.json`, add these scripts:\n\n```json title=\"package.json\"\n\"zip\": \"npx @h4ad/node-modules-packer ./ --include dist --output-path packages/[name-of-your-package]/prod\",\n\"update-function\": \"doctl serverless deploy .\",\n\"deploy\": \"npm run build && npm run zip && npm run update-function\"\n```\n\n> If you want to know more configurations of node-modules-packer, see [here](https://github.com/H4ad/node-modules-packer#examples).\n\nTo deploy, just run `npm run deploy` and that's it! Your API will be available for you to use.\n\n## Examples\n\nYou can see examples of how to use [here](https://github.com/H4ad/serverless-adapter-examples).\n"
  },
  {
    "path": "www/docs/main/handlers/firebase.mdx",
    "content": "---\ntitle: Firebase\ndescription: See more about how to integrate with Firebase Functions.\n---\n\n:::tip\n\nDon't know what a handler is? See the [Architecture](../architecture#handler) section.\n\n:::\n\n## Requirements\n\nFirst, install the types for this adapter:\n\n```bash\nnpm i --save firebase-functions firebase-admin\n```\n\n## V1 and V2\n\nIf you want to use Firebase Functions V1, use [HttpFirebaseHandler](../../api/Handlers/HttpFirebaseHandler).\n\nBut if you want to add support for V2, then use [HttpFirebaseV2Handler](../../api/Handlers/HttpFirebaseHandler/HttpFirebaseV2Handler).\n\n## Integrating with Http Events\n\nTo use, you can import [HttpFirebaseV2Handler](../../api/Handlers/HttpFirebaseHandler/HttpFirebaseV2Handler) and call the method [setHandler](../../api/ServerlessAdapter#method-sethandler), as per the code below:\n\n```ts title=\"index.ts\"\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\nimport { DummyAdapter } from '@h4ad/serverless-adapter/adapters/dummy';\nimport { HttpFirebaseV2Handler } from '@h4ad/serverless-adapter/handlers/firebase';\nimport { DummyResolver } from '@h4ad/serverless-adapter/resolvers/dummy';\nimport app from './app';\n\nexport const helloWorld = ServerlessAdapter.new(app)\n  .setHandler(new HttpFirebaseV2Handler({\n    // you can pass custom properties here, like: concurrency.\n  }))\n  .setResolver(new DummyResolver())\n  // choose the framework of your app\n  // .setFramework(new ExpressFramework())\n  .addAdapter(new DummyAdapter())\n  .build();\n\n// you can export more than one if you want\nexport const test = ServerlessAdapter.new(app)\n  .setHandler(new HttpFirebaseV2Handler())\n  .setResolver(new DummyResolver())\n  // choose the framework of your app\n  // .setFramework(new ExpressFramework())\n  .addAdapter(new DummyAdapter())\n  .build();\n```\n\n:::info About Resolver and Adapter\n\nYou should use `DummyResolver` and `DummyAdapter` because it's a requirement for the library, but `HttpFirebaseV2Handler` doesn't do anything with them,\nso you use those dummy versions just to satisfy the library requirements.\n\n:::\n\n## What about Cron, Pub/Sub, etc?\n\nI could not think yet in an API to handle those cases well,\nso currently I didn't add support to these type of Firebase Functions.\n\nIf you have some idea about a design for those APIs, [create an issue](https://github.com/H4ad/serverless-adapter/issues/new/choose).\n\n## Examples\n\nYou can see examples of how to use [here](https://github.com/H4ad/serverless-adapter-examples).\n\n"
  },
  {
    "path": "www/docs/main/handlers/gcp.mdx",
    "content": "---\ntitle: Google Cloud Functions\ndescription: See more about how to integrate with Google Cloud Functions.\n---\n\n:::tip\n\nDon't know what a handler is? See the [Architecture](../architecture#handler) section.\n\n:::\n\n## Requirements\n\nFirst, install the types for this adapter:\n\n```bash\nnpm i --save @google-cloud/functions-framework\n```\n\n## Integrating with Http Events\n\nTo use, you can import [GCPHandler](../../api/Handlers/GCPHandler) and call the method [setHandler](../../api/ServerlessAdapter#method-sethandler), as per the code below:\n\n```ts title=\"index.ts\"\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\nimport { DummyAdapter } from '@h4ad/serverless-adapter/adapters/dummy';\nimport { GCPHandler } from '@h4ad/serverless-adapter/handlers/gcp';\nimport { DummyResolver } from '@h4ad/serverless-adapter/resolvers/dummy';\nimport app from './app';\n\nconst functionName = 'helloWorld';\n\n// this handler don't need to export\nServerlessAdapter.new(app)\n  .setHandler(new GCPHandler(functionName))\n  .setResolver(new DummyResolver())\n  // choose the framework of your app\n  // .setFramework(new ExpressFramework())\n  .addAdapter(new DummyAdapter())\n  .build();\n```\n\nWhen defining `functionName`, on deploy, you MUST set the `--entry-point` flag when running `gcloud deploy` to the same value.\n\n:::danger Function Version\n\nYou MUST use `--gen2` flag when running `gcloud deploy`, this library was designed to only work with `gen2` of Google Cloud Function.\n\n:::\n\n:::info About Resolver and Adapter\n\nYou should use `DummyResolver` and `DummyAdapter` because it's a requirement for the library, but `GCPHandler` doesn't do anything with them,\nso you use those dummy versions just to satisfy the library requirements.\n\n:::\n\n## What about Pub/Sub, Storage, etc?\n\nI could not think yet in an API to handle those cases well,\nso currently I didn't add support to these type of Google Cloud Functions.\n\nIf you have some idea about a design for those APIs, [create an issue](https://github.com/H4ad/serverless-adapter/issues/new/choose).\n\n## Examples\n\nYou can see examples of how to use [here](https://github.com/H4ad/serverless-adapter-examples).\n\n"
  },
  {
    "path": "www/docs/main/handlers/huawei.mdx",
    "content": "---\r\ntitle: Huawei\r\ndescription: See more about how to integrate with Huawei.\r\n---\r\n\r\nIn Huawei, we added support to FunctionGraphV2 with Http Function and Event Function.\r\n\r\nThe difference between Http Function and Event Function is that in Http Function you must expose port 8000 and Huawei will proxy Api Gateway requests to your application.\r\nSo, on implementation, this library will create an http server to listen on port 8000 and forward the request to your framework.\r\n\r\nIn Event Function, you will receive the event from event source in the same way you receive in AWS, an object with some structure, you can see the supported event sources [here](https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0102.html).\r\n\r\n## Http Function\r\n\r\nTo integrate your app with Huawei FunctionGrapth with the Http Function type, you must do the following:\r\n\r\n```ts\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { ExpressFramework } from '@h4ad/serverless-adapter/frameworks/express';\r\nimport { HttpHuaweiHandler } from '@h4ad/serverless-adapter/handlers/huawei';\r\nimport { DummyResolver } from '@h4ad/serverless-adapter/resolvers/dummy';\r\nimport { DummyAdapter } from '@h4ad/serverless-adapter/adapters/dummy';\r\nimport app from './app';\r\n\r\n// instead exposing handler, you have the dispose function\r\n// this dispose function is never called\r\n// but you can to close the http server created with him\r\nconst dispose = ServerlessAdapter.new(app)\r\n    .setHandler(new HttpHuaweiHandler())\r\n    .setFramework(new ExpressFramework())\r\n    // dummy resolver and adapter is used because\r\n    // they are necessary in the core of the library to build\r\n    // but is optional to make huawei http function works.\r\n    .setResolver(new DummyResolver())\r\n    .addAdapter(new DummyAdapter())\r\n    .build();\r\n```\r\n\r\n> You don't need to expose a variable called `handler` when you choose Http Function, you just need to call build to the library create a http server.\r\n\r\nBy the way of Huawei architecture in Http Function, they have no use for Resolvers and Adapters, so you need to use the dummy versions because the library requires it.\r\n\r\n:::info ONE IMPORTANT THING\r\n\r\nYou need to configure a file called `bootstrap` in the root of folder that you upload to Huawei, is like the file `Procfile` but for Huawei.\r\n\r\nIn my setup, I configure like:\r\n```\r\nnode /opt/function/code/index.js\r\n```\r\n\r\nThe path `/opt/function/code` is where your code is uploaded when you deploy something and `index.js` is the file that contains the `ServerlessAdapter`.\r\n\r\nIn the end, the structure of the zip file you upload looks like this:\r\n\r\n- `bootstrap`\r\n- `index.js`\r\n\r\n:::\r\n\r\n## Event Function\r\n\r\nWith Http Function you need to use [HttpHuaweiHandler](./huawei#http-function),\r\nbut with Event Function you should use [DefaultHandler](./aws).\r\n\r\nSo, to add support to Api Gateway you do the following:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { HuaweiApiGatewayAdapter } from '@h4ad/serverless-adapter/adapters/huawei';\r\nimport { ExpressFramework } from '@h4ad/serverless-adapter/frameworks/express';\r\nimport { DefaultHandler } from '@h4ad/serverless-adapter/handlers/default';\r\nimport { CallbackResolver } from '@h4ad/serverless-adapter/resolvers/callback';\r\nimport app from './app';\r\n\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setFramework(new ExpressFramework())\r\n  .setHandler(new DefaultHandler())\r\n  .setResolver(new CallbackResolver())\r\n  .addAdapter(new HuaweiApiGatewayAdapter())\r\n  .build();\r\n```\r\n\r\n:::caution One important thing\r\n\r\nYou must use the callback resolver because I couldn't get it to work with the PromiseResolver.\r\nMaybe it's a bug in the library or something specific in Huawei, if you have a hint please create an issue.\r\n\r\n:::\r\n\r\n## Examples\r\n\r\nYou can see examples of how to use [here](https://github.com/H4ad/serverless-adapter-examples).\r\n\r\n## Sponsor\r\n\r\nThis handler was sponsored by [Liga](https://liga.facens.br/), if you want to built an app, site or game (mobile, AR or VR), send an email to [liga@facens.br].\r\n\r\n| <a href=\"https://liga.facens.br/\"><img height=\"50\" src=\"https://mlogu6g7z5ex.i.optimole.com/yEwfkqo-4R0ttNtd/w:auto/h:auto/q:mauto/f:avif/http://liga.facens.br/wp-content/uploads/2020/03/logo-1.png\" title=\"The LIGA logo\" width=\"100\"/></a> |\r\n|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\r\n"
  },
  {
    "path": "www/docs/main/intro.mdx",
    "content": "---\nsidebar_position: 1\n---\n\n# Introduction\n\nThis library was a refactored version of [@vendia/serverless-express](https://github.com/vendia/serverless-express), I\ncreate a new way to interact and extend event sources by creating contracts to abstract the integrations between each\nlibrary layer.\n\nWhy you would use this libray instead of [@vendia/serverless-express](https://github.com/vendia/serverless-express)?\n\n- Better APIs to extend library functionality.\n  - You don't need me to release a new version to integrate with the new event source, you can create an adapter and\n    just call the `addAdapter` method when building your handler.\n- All code can be extended, if you want to modify the current behavior you can.\n  - This is important because if you find a bug, you can quickly resolve it by extending the class, _and then you can\n    submit a PR to fix the bug_.\n- All code was written in Typescript.\n- Well documented, any method, class, or interface has comments to explain the behavior.\n- We have >99% coverage.\n\n## Support\n\nBy design we have these contracts that define the layers of the library: Frameworks, Adapters, Resolvers and Handlers.\n\n:::info\n\nIf you don't know what each thing means, see [Architecture](./architecture).\n\n:::\n\nCurrently, we support these clouds (handlers):\n\n- Azure by using ([AzureHandler](./handlers/azure))\n- AWS by using ([DefaultHandler](./handlers/aws))\n  - For [AWS Lambda Response Streaming](https://aws.amazon.com/blogs/compute/introducing-aws-lambda-response-streaming/), you should use ([AwsStreamHandler](./handlers/aws#aws-lambda-response-streaming))\n- Digital Ocean by using ([DigitalOceanHandler](./handlers/digital-ocean))\n- Firebase by using ([HttpFirebaseHandler](./handlers/firebase))\n- Huawei by using ([HttpHuaweiHandler](./handlers/huawei#http-function)) and ([EventHuaweiHandler](./handlers/huawei#event-function))\n\nAdditionally, we support these frameworks:\n\n- [Apollo Server](https://www.apollographql.com/docs/apollo-server/) by using ([ApolloServerFramework](./frameworks/apollo-server))\n- [Deepkit](https://docs.deepkit.io/) by using ([HttpDeepkitFramework](./frameworks/deepkit))\n- [Express](https://expressjs.com/) by using ([ExpressFramework](./frameworks/express))\n- [Fastify](https://www.fastify.io/) by using ([FastifyFramework](./frameworks/fastify))\n- [Hapi](https://hapi.dev/) by using ([HapiFramework](./frameworks/hapi))\n- [Koa](https://koajs.com/) by using ([KoaFramework](./frameworks/koa))\n- [NestJS](https://nestjs.com/), see the [documentation about](./frameworks/nestjs) to know how to integrate.\n- [tRPC](https://trpc.io/), see the [documentation about](./frameworks/trpc) to know how to integrate.\n\nAdditionally, we have some helper frameworks that you can combine with the above frameworks to give more power to your application:\n\n- Async Initialization by using ([LazyFramework](./frameworks/helpers/lazy))\n  - Use this framework to provide a way to create the instance of your app asynchronously.\n  - With him, you can create an instance of Express or Fastify asynchronously, [see the docs](./frameworks/helpers/lazy).\n- CORS support without rely on original framework with ([CorsFramework](./frameworks/helpers/cors))\n  - Use this framework to provide a way to handle CORS in frameworks like `trpc`, `deepkit` and others.\n  - Or use to get faster responses when method is `OPTIONS`.\n- Content Type parsing support without rely on original framework with ([BodyParserFramework](./frameworks/helpers/body-parser))\n  - Use this framework to provide a way to handle content type parsing in frameworks like `trpc`, `deepkit` and others.\n\nWe support these event sources:\n\n- AWS\n  - [AWS Load Balancer](https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html) by\n    using ([AlbAdapter](./adapters/aws/alb))\n  - [AWS Api Gateway V1](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html)\n    by using ([ApiGatewayV1Adapter](./adapters/aws/api-gateway-v1))\n  - [AWS Api Gateway V2](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html)\n    by using ([ApiGatewayV2Adapter](./adapters/aws/api-gateway-v2))\n  - [AWS Lambda Function URLs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html)\n    by using ([ApiGatewayV2Adapter](./adapters/aws/function-url))\n  - [AWS DynamoDB](https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html) by\n    using ([DynamoDBAdapter](./adapters/aws/dynamodb))\n  - [AWS Event Bridge / CloudWatch Events](https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents.html)\n    by using ([EventBridgeAdapter](./adapters/aws/event-bridge))\n  - [AWS Lambda Edge](https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html) by\n    using ([LambdaEdgeAdapter](./adapters/aws/lambda-edge))\n  - [AWS SNS](https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html) by\n    using ([SNSAdapter](./adapters/aws/sns))\n  - [AWS SQS](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html) by\n    using ([SQSAdapter](./adapters/aws/sqs))\n  - [AWS S3](https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html) by\n    using ([S3Adapter](./adapters/aws/s3))\n- Huawei\n  - [Http Function](https://support.huaweicloud.com/intl/en-us/usermanual-functiongraph/functiongraph_01_1442.html): Look [this section](./handlers/huawei#http-function).\n  - [Event Function](https://support.huaweicloud.com/intl/en-us/usermanual-functiongraph/functiongraph_01_1441.html): Look [this section](./handlers/huawei#event-function).\n    - [Api Gateway](https://support.huaweicloud.com/intl/en-us/devg-functiongraph/functiongraph_02_0102.html#functiongraph_02_0102__li5178638110137) by using ([HuaweiApiGatewayAdapter](./adapters/huawei/huawei-api-gateway)).\n- Azure\n  - [Http Trigger V4](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer?tabs=in-process&pivots=programming-language-javascript) by using ([HttpTriggerV4Adapter](./adapters/azure/http-trigger-v4)).\n- Digital Ocean\n  - [Functions](https://docs.digitalocean.com/products/functions/quickstart/sample-functions/) by using [DigitalOceanHandler](./handlers/digital-ocean).\n- Firebase\n  - [Http Events](https://firebase.google.com/docs/functions/http-events) using ([HttpFirebaseHandler](./handlers/firebase) and [HttpFirebaseV2Handler](./handlers/firebase)).\n- Google Cloud Functions (GCP)\n  - [Http Functions](https://cloud.google.com/functions/docs/console-quickstart) using ([GCPHandler](./handlers/gcp)).\n\nWe support these resolvers:\n\n- Promise by using ([PromiseResolver](./resolvers/promise))\n- Callback by using ([CallbackResolver](./resolvers/callback))\n- AWS Context by using ([AwsContextResolver](./resolvers/aws-context))\n\n## Why you create this library?\n\nThe real reason I created this library was because I wanted to add API Gateway and SQS support at the same time to save\nsome money. But, [@vendia/serverless-express](https://github.com/vendia/serverless-express) was not supported, so\nI [created a PR](https://github.com/vendia/serverless-express/pull/483) ~~but until I finished this library that PR was never accepted~~ and it was merged but it took so long.\n\nSo I build my own library based on that library with better APIs so I never have to wait for the maintainer to accept my\nPR just to extend the library's functionality :)\n\n## Breaking Changes\n\nI will not consider updating/breaking compatibility of a NodeJS framework as a breaking change,\nbecause I had a lot of supported frameworks and if I created a major version for each one it would be a mess.\n\nSo if you want predictability, pin the version with `~` instead of `^`.\n\n## Credits\n\nHonestly, I just refactored all the code that the @vendia team and many other contributors wrote, thanks so much to them\nfor existing and giving us a brilliant library that is the core of my current company.\n"
  },
  {
    "path": "www/docs/main/resolvers/aws-context.mdx",
    "content": "---\r\ntitle: AWS Context\r\nposition: 3\r\ndescription: See more about the AWS Context Resolver.\r\n---\r\n\r\n:::tip\r\n\r\nDon't know what a resolver is? See the [Architecture](../architecture#resolver) section.\r\n\r\n:::\r\n\r\n:::note Deprecated\r\n\r\nFrom the AWS Documentation, describing the functions used in this resolver: Functions for compatibility with earlier Node.js Runtime v0.10.42. No longer documented, so they are deprecated, but they still work as of the 12.x runtime, so they are not removed from the types.\r\n\r\n:::\r\n\r\nThis resolver only works in AWS and it was created just to be fully compatible with the resolution mode of [@vendia/serverless-express](https://github.com/vendia/serverless-express/blob/mainline/src/make-resolver.js#L9).\r\n\r\nWhen the handler is created with [getHandler](../../api/Contracts/HandlerContract#method-gethandler), it will return void\r\nand the cloud will wait until the event loop is empty.\r\nThis happens when your framework sends the response and the adapter transforms the response the way your cloud can handle,\r\nat this point the response will be passed to the functions `succeed` or `fail` that is exposed by `context` object.\r\n\r\nYou can use this resolver only with AWS.\r\n\r\n:::caution AWS\r\n\r\nTo use this resolver on AWS, you MUST leave [callbackWaitsForEmptyEventLoop](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-context.html) as true, otherwise, AWS will not wait for this resolver to resolve.\r\n\r\n:::\r\n\r\n# Usage\r\n\r\nTo use, you can import and call the method [setResolver](../../api/ServerlessAdapter#method-setresolver), as per the code below:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { AwsContextResolver } from '@h4ad/serverless-adapter/resolvers/aws-context';\r\n\r\nconst express = require('express');\r\n\r\nconst app = express();\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setResolver(new AwsContextResolver())\r\n  // continue to set the other options here.\r\n  //.setFramework(new ExpressFramework())\r\n  //.setHandler(new DefaultHandler())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n"
  },
  {
    "path": "www/docs/main/resolvers/callback.mdx",
    "content": "---\r\ntitle: Callback\r\nposition: 2\r\ndescription: See more about the Callback Resolver.\r\n---\r\n\r\n:::tip\r\n\r\nDon't know what a resolver is? See the [Architecture](../architecture#resolver) section.\r\n\r\n:::\r\n\r\nThe best and most agnostic resolver (for sure) is using callback, generally every serverless environment supports callback as the third argument of the handler.\r\n\r\nWhen the handler is created with [getHandler](../../api/Contracts/HandlerContract#method-gethandler), it will return void\r\nand the cloud will wait until the event loop is empty.\r\nThis happens when your framework sends the response and the adapter transforms the response the way your cloud can handle,\r\nat this point the response will be passed to the callback and then the event loop will be empty.\r\n\r\nYou can use this resolver with any cloud, with any framework or any adapter.\r\n\r\n:::caution AWS\r\n\r\nTo use this resolver on AWS, you MUST leave [callbackWaitsForEmptyEventLoop](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-context.html) as true, otherwise, AWS will not wait for this resolver to resolve.\r\n\r\n:::\r\n\r\n# Usage\r\n\r\nTo use, you can import and call the method [setResolver](../../api/ServerlessAdapter#method-setresolver), as per the code below:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { CallbackResolver } from '@h4ad/serverless-adapter/resolvers/callback';\r\n\r\nconst express = require('express');\r\n\r\nconst app = express();\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setResolver(new CallbackResolver())\r\n  // continue to set the other options here.\r\n  //.setFramework(new ExpressFramework())\r\n  //.setHandler(new DefaultHandler())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nTo know more about how AWS deals with callback handlers, see [NodeJS Handler](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html) section.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docs/main/resolvers/promise.mdx",
    "content": "---\r\ntitle: Promise\r\nposition: 1\r\ndescription: See more about the Promise Resolver.\r\n---\r\n\r\n:::tip\r\n\r\nDon't know what a resolver is? See the [Architecture](../architecture#resolver) section.\r\n\r\n:::\r\n\r\nThe best and most agnostic resolver is using promise, generally every serverless environment supports asynchronous handlers.\r\n\r\nWhen the handler is created with [getHandler](../../api/Contracts/HandlerContract#method-gethandler), it will return an promise\r\nwhich is resolved when your framework send the response and the adapter transform the response in the way of your cloud can handle.\r\n\r\nYou can use this resolver with any cloud (except Huawei), with any framework or any adapter.\r\n\r\n:::caution\r\n\r\nOnly Huawei doesn't support Promise, or it was buggy in my time, so I suggest you use [Callback Resolver](./callback).\r\n\r\n:::\r\n\r\n# Usage\r\n\r\nTo use, you can import and call the method [setResolver](../../api/ServerlessAdapter#method-setresolver), as per the code below:\r\n\r\n```ts title=\"index.ts\"\r\nimport { ServerlessAdapter } from '@h4ad/serverless-adapter';\r\nimport { PromiseResolver } from '@h4ad/serverless-adapter/resolvers/promise';\r\n\r\nconst express = require('express');\r\n\r\nconst app = express();\r\nexport const handler = ServerlessAdapter.new(app)\r\n  .setResolver(new PromiseResolver())\r\n  // continue to set the other options here.\r\n  //.setFramework(new ExpressFramework())\r\n  //.setHandler(new DefaultHandler())\r\n  //.addAdapter(new AlbAdapter())\r\n  //.addAdapter(new SQSAdapter())\r\n  //.addAdapter(new SNSAdapter())\r\n  // after put all methods necessary, just call the build method.\r\n  .build();\r\n```\r\n\r\n:::tip\r\n\r\nTo know more about how AWS deals with async handlers, see [NodeJS Handler](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html) section.\r\n\r\n:::\r\n"
  },
  {
    "path": "www/docusaurus.config.js",
    "content": "// @ts-check\n// Note: type annotations allow type checking and IDEs autocompletion\n\nconst {\n  themes: { dracula: darkCodeTheme, github: lightCodeTheme },\n} = require('prism-react-renderer');\n\n/** @type {import('@docusaurus/types').Config} */\nconst config = {\n  title: 'Serverless Adapter',\n  tagline:\n    'Run REST APIs and other web applications using your existing Node.js application framework (NestJS, Express, Koa, Hapi, Fastify and many others), on top of AWS, Azure, Digital Ocean and many other clouds.',\n  url: 'https://serverless-adapter.viniciusl.com.br',\n  baseUrl: '/',\n  onBrokenLinks: 'throw',\n  onBrokenMarkdownLinks: 'warn',\n  favicon: 'img/favicon.ico',\n  organizationName: 'h4ad', // Usually your GitHub org/user name.\n  projectName: 'serverless-adapter', // Usually your repo name.\n  deploymentBranch: 'gh-pages',\n  trailingSlash: false,\n  plugins: [\n    [\n      '@docusaurus/plugin-client-redirects',\n      {\n        redirects: [\n          {\n            from: '/docs/main/adapters/introduction',\n            to: '/docs/main/advanced/adapters/introduction',\n          },\n          {\n            from: '/docs/main/adapters/creating-an-adapter',\n            to: '/docs/main/advanced/adapters/creating-an-adapter',\n          },\n          {\n            from: '/docs/main/frameworks/cors',\n            to: '/docs/main/frameworks/helpers/cors',\n          },\n          {\n            from: '/docs/main/frameworks/lazy',\n            to: '/docs/main/frameworks/helpers/lazy',\n          },\n          {\n            from: '/docs/main/handlers/default',\n            to: '/docs/main/handlers/aws',\n          },\n        ],\n      },\n    ],\n  ],\n  presets: [\n    [\n      'classic',\n      /** @type {import('@docusaurus/preset-classic').Options} */\n      ({\n        docs: {\n          sidebarPath: require.resolve('./sidebars.js'),\n          // Please change this to your repo.\n          editUrl: 'https://github.com/H4ad/serverless-adapter/tree/main/www/',\n        },\n        blog: {\n          showReadingTime: true,\n          // Please change this to your repo.\n          editUrl: 'https://github.com/H4ad/serverless-adapter/tree/main/www/',\n        },\n        theme: {\n          customCss: require.resolve('./src/css/custom.css'),\n        },\n      }),\n    ],\n  ],\n\n  themeConfig:\n    /** @type {import('@docusaurus/preset-classic').ThemeConfig} */\n    ({\n      navbar: {\n        title: 'Serverless Adapter',\n        logo: {\n          alt: 'Serverless Adapter',\n          src: 'img/logo.svg',\n        },\n        items: [\n          {\n            type: 'doc',\n            docId: 'main/intro',\n            position: 'left',\n            label: 'Docs',\n            sidebarId: 'main',\n          },\n          { to: '/blog', label: 'Blog', position: 'left' },\n          {\n            type: 'docSidebar',\n            position: 'left',\n            sidebarId: 'api',\n            label: 'API',\n          },\n          {\n            href: 'https://github.com/h4ad/serverless-adapter',\n            label: 'GitHub',\n            position: 'right',\n          },\n        ],\n      },\n      footer: {\n        style: 'dark',\n        links: [\n          {\n            title: 'About Maintainer',\n            items: [\n              {\n                label: 'Twitter',\n                href: 'https://twitter.com/vinii_joga10',\n              },\n              {\n                label: 'Linkedin',\n                href: 'https://www.linkedin.com/in/vinilourenco/',\n              },\n            ],\n          },\n          {\n            title: 'More',\n            items: [\n              {\n                label: 'Blog',\n                to: '/blog',\n              },\n              {\n                label: 'GitHub',\n                href: 'https://github.com/h4ad/serverless-adapter',\n              },\n            ],\n          },\n          {\n            title: 'Sponsors',\n            items: [\n              {\n                label: 'LIGA',\n                to: 'https://liga.facens.br/',\n              },\n            ],\n          },\n        ],\n        copyright: `Copyright © ${new Date().getFullYear()} Serverless Adapter. Built with Docusaurus.`,\n      },\n      prism: {\n        theme: lightCodeTheme,\n        darkTheme: darkCodeTheme,\n      },\n      algolia: {\n        // The application ID provided by Algolia\n        appId: 'G7D9713FAL',\n\n        // Public API key: it is safe to commit it\n        apiKey: '935039e719649426185a3272f7875e62',\n\n        indexName: 'serverless-adapter',\n\n        // Optional: see doc section below\n        contextualSearch: true,\n\n        // Optional: Specify domains where the navigation should occur through window.location instead on history.push. Useful when our Algolia config crawls multiple documentation sites and we want to navigate with window.location.href to them.\n        // externalUrlRegex: 'external\\\\.com|domain\\\\.com',\n\n        // Optional: Algolia search parameters\n        // searchParameters: {},\n\n        // Optional: path for search page that enabled by default (`false` to disable it)\n        searchPagePath: 'search',\n\n        //... other Algolia params\n      },\n    }),\n};\n\nmodule.exports = config;\n"
  },
  {
    "path": "www/package.json",
    "content": "{\n  \"name\": \"docs\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"start\": \"docusaurus start\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\",\n    \"clear\": \"docusaurus clear\",\n    \"serve\": \"docusaurus serve\",\n    \"write-translations\": \"docusaurus write-translations\",\n    \"write-heading-ids\": \"docusaurus write-heading-ids\",\n    \"typecheck\": \"tsc\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"3.0.1\",\n    \"@docusaurus/plugin-client-redirects\": \"3.0.1\",\n    \"@docusaurus/preset-classic\": \"3.0.1\",\n    \"@mdx-js/react\": \"3.0.0\",\n    \"clsx\": \"2.0.0\",\n    \"prism-react-renderer\": \"2.3.1\",\n    \"react\": \"18.2.0\",\n    \"react-dom\": \"18.2.0\"\n  },\n  \"devDependencies\": {\n    \"@docusaurus/module-type-aliases\": \"3.0.1\",\n    \"@tsconfig/docusaurus\": \"2.0.2\",\n    \"typescript\": \"5.3.3\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.5%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  }\n}\n"
  },
  {
    "path": "www/sidebars.js",
    "content": "/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that group\n - provide next/previous navigation\n\n The sidebars can be generated from the filesystem, or explicitly defined here.\n\n Create as many sidebars as you want.\n */\n\n// @ts-check\n\n/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */\nconst sidebars = {\n  // By default, Docusaurus generates a sidebar from the docs folder structure\n  main: [\n    'main/intro',\n    'main/architecture',\n    {\n      type: 'category',\n      label: 'Getting Started',\n      link: {\n        type: 'generated-index',\n      },\n      collapsed: false,\n      items: [\n        'main/getting-started/installation',\n        'main/getting-started/usage',\n        'main/getting-started/customizing',\n        'main/getting-started/examples',\n      ],\n    },\n    {\n      type: 'category',\n      label: 'Adapters',\n      link: {\n        type: 'generated-index',\n      },\n      collapsed: true,\n      items: [\n        {\n          type: 'category',\n          label: 'AWS',\n          collapsed: true,\n          link: {\n            type: 'generated-index',\n          },\n          items: [\n            {\n              type: 'autogenerated',\n              dirName: 'main/adapters/aws',\n            },\n          ],\n        },\n        {\n          type: 'category',\n          label: 'Azure',\n          collapsed: true,\n          link: {\n            type: 'generated-index',\n          },\n          items: [\n            {\n              type: 'autogenerated',\n              dirName: 'main/adapters/azure',\n            },\n          ],\n        },\n        {\n          type: 'category',\n          label: 'Digital Ocean',\n          collapsed: true,\n          link: {\n            type: 'generated-index',\n          },\n          items: [\n            {\n              type: 'autogenerated',\n              dirName: 'main/adapters/digital-ocean',\n            },\n          ],\n        },\n        'main/adapters/firebase',\n        {\n          type: 'category',\n          label: 'Huawei',\n          collapsed: true,\n          link: {\n            type: 'generated-index',\n          },\n          items: [\n            {\n              type: 'autogenerated',\n              dirName: 'main/adapters/huawei',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      type: 'category',\n      label: 'Handlers',\n      link: {\n        type: 'generated-index',\n      },\n      collapsed: true,\n      items: [\n        {\n          type: 'autogenerated',\n          dirName: 'main/handlers',\n        },\n      ],\n    },\n    {\n      type: 'category',\n      label: 'Resolvers',\n      link: {\n        type: 'generated-index',\n      },\n      collapsed: true,\n      items: [\n        'main/resolvers/aws-context',\n        'main/resolvers/callback',\n        'main/resolvers/promise',\n      ],\n    },\n    {\n      type: 'category',\n      label: 'Frameworks',\n      link: {\n        type: 'generated-index',\n      },\n      collapsed: true,\n      items: [\n        'main/frameworks/apollo-server',\n        'main/frameworks/deepkit',\n        'main/frameworks/express',\n        'main/frameworks/fastify',\n        'main/frameworks/hapi',\n        'main/frameworks/koa',\n        'main/frameworks/nestjs',\n        'main/frameworks/polka',\n        'main/frameworks/trpc',\n        {\n          type: 'category',\n          label: 'Helpers',\n          link: {\n            type: 'generated-index',\n          },\n          collapsed: false,\n          items: [\n            {\n              type: 'autogenerated',\n              dirName: 'main/frameworks/helpers',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      type: 'category',\n      label: 'Advanced',\n      link: {\n        type: 'generated-index',\n      },\n      collapsed: true,\n      items: [\n        {\n          type: 'category',\n          label: 'Adapters',\n          link: {\n            type: 'generated-index',\n          },\n          collapsed: true,\n          items: [\n            'main/advanced/adapters/introduction',\n            'main/advanced/adapters/creating-an-adapter',\n          ],\n        },\n      ],\n    },\n  ],\n  api: [\n    {\n      type: 'autogenerated',\n      dirName: 'api',\n    },\n  ],\n};\n\nmodule.exports = sidebars;\n"
  },
  {
    "path": "www/src/components/BrowserWindow/index.tsx",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport clsx from 'clsx';\nimport React, { type ReactNode } from 'react';\n\nimport styles from './styles.module.css';\n\ninterface Props {\n  children: ReactNode;\n  minHeight: number;\n  url: string;\n}\n\nexport default function BrowserWindow({\n  children,\n  minHeight,\n  url = 'http://localhost:3000',\n}: Props): JSX.Element {\n  return (\n    <div className={styles.browserWindow} style={{ minHeight }}>\n      <div className={styles.browserWindowHeader}>\n        <div className={styles.buttons}>\n          <span className={styles.dot} style={{ background: '#f25f58' }} />\n          <span className={styles.dot} style={{ background: '#fbbe3c' }} />\n          <span className={styles.dot} style={{ background: '#58cb42' }} />\n        </div>\n        <div className={clsx(styles.browserWindowAddressBar, 'text--truncate')}>\n          <a href={url} target=\"_blank\" rel=\"noopener\">\n            {url}\n          </a>\n        </div>\n        <div className={styles.browserWindowMenuIcon}>\n          <div>\n            <span className={styles.bar} />\n            <span className={styles.bar} />\n            <span className={styles.bar} />\n          </div>\n        </div>\n      </div>\n\n      <div className={styles.browserWindowBody}>{children}</div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "www/src/components/BrowserWindow/styles.module.css",
    "content": "/**\r\n * Copyright (c) Facebook, Inc. and its affiliates.\r\n *\r\n * This source code is licensed under the MIT license found in the\r\n * LICENSE file in the root directory of this source tree.\r\n */\r\n\r\n.browserWindow {\r\n  border: 3px solid #444950;\r\n  border-radius: 0.4rem;\r\n  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .1);\r\n  margin-bottom: 1.25rem;\r\n}\r\n\r\n.browserWindowHeader {\r\n  align-items: center;\r\n  background: #444950;\r\n  display: flex;\r\n  padding: 0.5rem 1rem;\r\n}\r\n\r\n.row::after {\r\n  content: '';\r\n  display: table;\r\n  clear: both;\r\n}\r\n\r\n.buttons {\r\n  white-space: nowrap;\r\n}\r\n\r\n.right {\r\n  align-self: center;\r\n  width: 10%;\r\n}\r\n\r\n[data-theme='light'] {\r\n  --ifm-background-color: #fff;\r\n}\r\n\r\n.browserWindowAddressBar {\r\n  flex: 1 0;\r\n  margin: 0 1rem 0 0.5rem;\r\n  border-radius: 12.5px;\r\n  background-color: var(--ifm-background-color);\r\n  color: #444950;\r\n  padding: 5px 15px;\r\n  font: 400 13px Arial, sans-serif;\r\n  user-select: none;\r\n}\r\n\r\n[data-theme='dark'] .browserWindowAddressBar {\r\n  color: #dadde1;\r\n}\r\n\r\n.dot {\r\n  margin-right: 6px;\r\n  margin-top: 4px;\r\n  height: 12px;\r\n  width: 12px;\r\n  background-color: #bbb;\r\n  border-radius: 50%;\r\n  display: inline-block;\r\n}\r\n\r\n.browserWindowMenuIcon {\r\n  margin-left: auto;\r\n}\r\n\r\n.bar {\r\n  width: 17px;\r\n  height: 3px;\r\n  background-color: #aaa;\r\n  margin: 3px 0;\r\n  display: block;\r\n}\r\n\r\n.browserWindowBody {\r\n  background-color: var(--ifm-background-color);\r\n  border-bottom-left-radius: inherit;\r\n  border-bottom-right-radius: inherit;\r\n  padding: 1rem;\r\n}\r\n\r\n.browserWindowBody *:last-child {\r\n  margin-bottom: 0;\r\n}\r\n"
  },
  {
    "path": "www/src/components/HomepageFeatures/index.tsx",
    "content": "import clsx from 'clsx';\nimport React from 'react';\nimport styles from './styles.module.css';\n\ntype FeatureItem = {\n  title: string;\n  description: JSX.Element;\n};\n\nconst FeatureList: FeatureItem[] = [\n  {\n    title: 'Easy to Use & Extensible',\n    description: (\n      <>The library was designed to be very extensible and easy to use.</>\n    ),\n  },\n  {\n    title: 'One library, many Serverless environments',\n    description: (\n      <>\n        We currently support AWS, Azure, Firebase, Digital Ocean, Google Cloud Functions and Huawei.\n      </>\n    ),\n  },\n  {\n    title: 'Fully Typed & Tested',\n    description: (\n      <>\n        The entire library was written with typescript to give the developer the\n        best experience and we have 100% coverage.\n      </>\n    ),\n  },\n];\n\nfunction Feature({ title, description }: FeatureItem) {\n  return (\n    <div className={clsx('col col--4 mt-4')}>\n      <div className=\"text--center padding-horiz--md\">\n        <h3>{title}</h3>\n        <p>{description}</p>\n      </div>\n    </div>\n  );\n}\n\nexport default function HomepageFeatures(): JSX.Element {\n  return (\n    <section className={styles.features}>\n      <div className=\"container\">\n        <div className=\"row\">\n          {FeatureList.map((props, idx) => (\n            <Feature key={idx} {...props} />\n          ))}\n        </div>\n      </div>\n    </section>\n  );\n}\n"
  },
  {
    "path": "www/src/components/HomepageFeatures/styles.module.css",
    "content": ".features {\n  display: flex;\n  align-items: center;\n  padding: 2rem 0;\n  width: 100%;\n}\n\n.mt-5 {\n  margin-top: 2rem;\n}\n"
  },
  {
    "path": "www/src/components/HowToStart/index.tsx",
    "content": "import Link from '@docusaurus/Link';\nimport CodeBlock from '@theme/CodeBlock';\nimport React from 'react';\nimport styles from './styles.module.css';\n\nexport default function HowToStart(): JSX.Element {\n  return (\n    <section className={styles.howto}>\n      <div className={styles.howtoContainer}>\n        <div className=\"row\">\n          <h1>To start, first, install the library with:</h1>\n        </div>\n        <div className=\"row\">\n          <div className={styles.exampleContainer}>\n            <CodeBlock language=\"bash\">\n              npm i --save @h4ad/serverless-adapter\n            </CodeBlock>\n          </div>\n        </div>\n        <div className={styles.exampleContainer}>\n          <p>\n            And then you can add support, for example, to{' '}\n            <Link to=\"/docs/main/adapters/aws/api-gateway-v2\">\n              AWS Api Gateway V2\n            </Link>\n            {' and '}\n            <Link to=\"/docs/main/adapters/aws/sqs\">AWS SQS</Link> to your\n            Express App with:\n          </p>\n          <div>\n            <CodeBlock\n              language=\"tsx\"\n              title=\"index.ts\"\n            >{`import { ServerlessAdapter } from '@h4ad/serverless-adapter';\nimport { ApiGatewayV2Adapter, SQSAdapter } from '@h4ad/serverless-adapter/lib/adapters/aws';\nimport { ExpressFramework } from '@h4ad/serverless-adapter/lib/frameworks/express';\nimport { DefaultHandler } from '@h4ad/serverless-adapter/lib/handlers/default';\nimport { PromiseResolver } from '@h4ad/serverless-adapter/lib/resolvers/promise';\nimport app from './app';\n\nexport const handler = ServerlessAdapter.new(app)\n  .setFramework(new ExpressFramework())\n  .setHandler(new DefaultHandler())\n  .setResolver(new PromiseResolver())\n  .addAdapter(new ApiGatewayV2Adapter())\n  .addAdapter(new SQSAdapter())\n  .build();\n            `}</CodeBlock>\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n}\n"
  },
  {
    "path": "www/src/components/HowToStart/styles.module.css",
    "content": ".howto {\n  padding: 2rem 0;\n  width: 100%;\n}\n\n.howtoContainer {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n\n.howto .row {\n  display: flex;\n  flex-direction: column;\n}\n\n.exampleContainer {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n\n.mt-5 {\n  margin-top: 2rem;\n}\n"
  },
  {
    "path": "www/src/css/custom.css",
    "content": "/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n/* You can override the default Infima variables here. */\n:root {\n  --ifm-color-primary: #2e8555;\n  --ifm-color-primary-dark: #29784c;\n  --ifm-color-primary-darker: #277148;\n  --ifm-color-primary-darkest: #205d3b;\n  --ifm-color-primary-light: #33925d;\n  --ifm-color-primary-lighter: #359962;\n  --ifm-color-primary-lightest: #3cad6e;\n  --ifm-code-font-size: 95%;\n}\n\n/* For readability concerns, you should choose a lighter palette in dark mode. */\n[data-theme='dark'] {\n  --ifm-color-primary: #25c2a0;\n  --ifm-color-primary-dark: #21af90;\n  --ifm-color-primary-darker: #1fa588;\n  --ifm-color-primary-darkest: #1a8870;\n  --ifm-color-primary-light: #29d5b0;\n  --ifm-color-primary-lighter: #32d8b4;\n  --ifm-color-primary-lightest: #4fddbf;\n}\n\n.docusaurus-highlight-code-line {\n  background-color: rgba(0, 0, 0, 0.1);\n  display: block;\n  margin: 0 calc(-1 * var(--ifm-pre-padding));\n  padding: 0 var(--ifm-pre-padding);\n}\n\n[data-theme='dark'] .docusaurus-highlight-code-line {\n  background-color: rgba(0, 0, 0, 0.3);\n}\n\nhtml {\n  scroll-behavior: smooth;\n}\n"
  },
  {
    "path": "www/src/pages/index.module.css",
    "content": "/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  padding: 4rem 0;\n  text-align: center;\n  position: relative;\n  overflow: hidden;\n}\n\n@media screen and (max-width: 996px) {\n  .heroBanner {\n    padding: 2rem;\n  }\n}\n\n.buttons {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n"
  },
  {
    "path": "www/src/pages/index.tsx",
    "content": "import Link from '@docusaurus/Link';\nimport useDocusaurusContext from '@docusaurus/useDocusaurusContext';\nimport HomepageFeatures from '@site/src/components/HomepageFeatures';\nimport HowToStart from '@site/src/components/HowToStart';\nimport Layout from '@theme/Layout';\nimport clsx from 'clsx';\nimport React from 'react';\nimport styles from './index.module.css';\n\nfunction HomepageHeader() {\n  const { siteConfig } = useDocusaurusContext();\n  return (\n    <header className={clsx('hero hero--primary', styles.heroBanner)}>\n      <div className=\"container\">\n        <h1 className=\"hero__title\">{siteConfig.title}</h1>\n        <p className=\"hero__subtitle\">{siteConfig.tagline}</p>\n        <div className={styles.buttons}>\n          <Link\n            className=\"button button--secondary button--lg\"\n            to=\"/docs/main/intro\"\n          >\n            Introduction\n          </Link>\n        </div>\n      </div>\n    </header>\n  );\n}\n\nexport default function Home(): JSX.Element {\n  const { siteConfig } = useDocusaurusContext();\n  return (\n    <Layout\n      title={`Hello from ${siteConfig.title}`}\n      description=\"Description will go into a meta tag in <head />\"\n    >\n      <HomepageHeader />\n      <main>\n        <HomepageFeatures />\n        <HowToStart />\n      </main>\n    </Layout>\n  );\n}\n"
  },
  {
    "path": "www/static/.nojekyll",
    "content": ""
  },
  {
    "path": "www/static/CNAME",
    "content": "serverless-adapter.viniciusl.com.br\n"
  },
  {
    "path": "www/tsconfig.json",
    "content": "{\n  // This file is not used in compilation. It is here just for a nice editor experience.\n  \"extends\": \"@tsconfig/docusaurus/tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\"\n  }\n}\n"
  }
]