[
  {
    "path": ".bazelci/presubmit.yml",
    "content": "---\n# TODO(yannic): Enable buildifier and test on Windows and RBE (both unsupported by rules_closure).\nplatforms:\n  macos:\n    build_targets:\n      - //...\n    test_targets:\n      - //...\n\n  ubuntu1804:\n    build_targets:\n      - //...\n    test_targets:\n      - //...\n"
  },
  {
    "path": ".bazelignore",
    "content": "# //third_party conatins git submodules.\nthird_party/\n"
  },
  {
    "path": ".bazelrc",
    "content": "# Common build settings for unix-like systems\nbuild --copt=-Wno-error=deprecated-declarations\nbuild --host_copt=-Wno-error=deprecated-declarations\n\n# Required until this is the default; expected in Bazel 7\ncommon --enable_bzlmod\n\n# Per-user settings (gitignored). Keep last so local flags can override.\n# Docs: https://bazel.build/configure/best-practices#bazelrc\ntry-import %workspace%/.bazelrc.user\n"
  },
  {
    "path": ".bazelrc.windows",
    "content": "# This is a Windows-specific bazelrc file for use in GitHub Actions.\n# It contains settings from the main .bazelrc file that are relevant for Windows builds.\n\n# Windows specific settings\nbuild --copt=-DABSL_HAVE_WORKING_GCC_WNO_DEPRECATED_DECLARATIONS=0\nbuild --host_copt=-DABSL_HAVE_WORKING_GCC_WNO_DEPRECATED_DECLARATIONS=0\n\n# Required until this is the default; expected in Bazel 7\ncommon --enable_bzlmod\n\n# Per-user settings (gitignored). Keep last so local flags can override.\n# Docs: https://bazel.build/configure/best-practices#bazelrc\ntry-import %workspace%/.bazelrc.user\n"
  },
  {
    "path": ".dockerignore",
    "content": "**/dist\n**/node_modules\npackages/grpc-web/generated\n"
  },
  {
    "path": ".github/workflows/make-plugin-linux.yml",
    "content": "name: Make Linux Plugin\n\non:\n  push:\n    paths:\n      - .github/workflows/make-plugin-linux.yml\n  pull_request:\n    paths:\n      - .github/workflows/make-plugin-linux.yml\n  workflow_dispatch:\n    inputs:\n      version_number:\n        description: 'Version number'\n        required: true\n        default: '2.x.x'\n\njobs:\n  build:\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-22.04, ubuntu-22.04-arm]\n    runs-on: ${{ matrix.os }}\n    steps:\n    - uses: actions/checkout@v4\n    - name: Compute VERSION_NUMBER\n      run: |\n        INPUT_VERSION=\"${{ github.event.inputs.version_number }}\"\n        if [ -n \"$INPUT_VERSION\" ]; then\n          VERSION=\"$INPUT_VERSION\"\n        else\n          VERSION=\"$GITHUB_REF_NAME\"\n        fi\n        VERSION=\"${VERSION//\\//-}\"\n        echo \"VERSION_NUMBER=$VERSION\" >> \"$GITHUB_ENV\"\n        echo \"Computed VERSION_NUMBER=$VERSION\"\n    - name: Compute ARCH suffix and artifact name\n      id: meta\n      run: |\n        ARCH=$(uname -m)\n        case \"$ARCH\" in\n          aarch64|arm64)\n            ARCH_SUFFIX=\"aarch64\"\n            ;;\n          x86_64|amd64)\n            ARCH_SUFFIX=\"x86_64\"\n            ;;\n          *)\n            echo \"Unsupported architecture: $ARCH\" >&2\n            exit 1\n            ;;\n        esac\n        ARTIFACT=\"protoc-gen-grpc-web-${VERSION_NUMBER}-linux-${ARCH_SUFFIX}\"\n        echo \"ARTIFACT=$ARTIFACT\" >> \"$GITHUB_ENV\"\n        echo \"artifact=$ARTIFACT\" >> \"$GITHUB_OUTPUT\"\n        echo \"Will produce artifact: $ARTIFACT\"\n    - name: Install Bazelisk (Bazel)\n      run: |\n        sudo apt-get update\n        sudo apt-get install -y unzip zip\n        ARCH=$(uname -m)\n        case \"$ARCH\" in\n          aarch64|arm64)\n            BAZELISK_URL=\"https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-arm64\"\n            ;;\n          x86_64|amd64)\n            BAZELISK_URL=\"https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-amd64\"\n            ;;\n          *)\n            echo \"Unsupported architecture for Bazelisk: $ARCH\" >&2\n            exit 1\n            ;;\n        esac\n        echo \"Downloading Bazelisk from $BAZELISK_URL\"\n        sudo curl -L -o /usr/local/bin/bazelisk \"$BAZELISK_URL\"\n        sudo chmod +x /usr/local/bin/bazelisk\n        # Also provide `bazel` symlink for tools that expect it\n        sudo ln -sf /usr/local/bin/bazelisk /usr/local/bin/bazel\n        bazelisk version\n    - name: Build protoc-gen-grpc-web with Bazel (older glibc baseline)\n      run: |\n        # Partially static link libstdc++/libgcc to reduce GLIBCXX constraints\n        bazelisk build \\\n          --linkopt=-static-libstdc++ \\\n          --linkopt=-static-libgcc \\\n          //javascript/net/grpc/web/generator:protoc-gen-grpc-web\n    - name: Move artifact\n      run: |\n        mv bazel-bin/javascript/net/grpc/web/generator/protoc-gen-grpc-web \\\n          ./${ARTIFACT}\n    - name: Generate sha256\n      run: |\n        openssl dgst -sha256 -r -out ${ARTIFACT}.sha256 \\\n          ${ARTIFACT}\n    - name: Verify sha256\n      run: sha256sum -c ${ARTIFACT}.sha256\n    - name: Upload artifacts\n      uses: actions/upload-artifact@v4\n      with:\n        name: ${{ steps.meta.outputs.artifact }}\n        path: protoc-gen-grpc-web*\n"
  },
  {
    "path": ".github/workflows/make-plugin-mac-os.yml",
    "content": "name: Make macOS Plugin\n\non:\n  push:\n    paths:\n      - .github/workflows/make-plugin-mac-os.yml\n  pull_request:\n    paths:\n      - .github/workflows/make-plugin-mac-os.yml\n  workflow_dispatch:\n    inputs:\n      version_number:\n        description: 'Version number'\n        required: true\n        default: '2.x.x'\n\njobs:\n  build:\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [macos-13, macos-14]\n    runs-on: ${{ matrix.os }}\n    steps:\n      - uses: actions/checkout@v4\n      - name: Compute VERSION_NUMBER\n        run: |\n          INPUT_VERSION=\"${{ github.event.inputs.version_number }}\"\n          if [ -n \"$INPUT_VERSION\" ]; then\n            VERSION=\"$INPUT_VERSION\"\n          else\n            VERSION=\"$GITHUB_REF_NAME\"\n          fi\n          # Minimal sanitization: replace slashes with dashes to keep filenames valid\n          VERSION=\"${VERSION//\\//-}\"\n          echo \"VERSION_NUMBER=$VERSION\" >> \"$GITHUB_ENV\"\n          echo \"Computed VERSION_NUMBER=$VERSION\"\n      - name: Compute ARCH suffix and artifact name\n        id: meta\n        run: |\n          ARCH=$(uname -m)\n          case \"$ARCH\" in\n            arm64)\n              ARCH_SUFFIX=\"aarch64\"\n              ;;\n            x86_64)\n              ARCH_SUFFIX=\"x86_64\"\n              ;;\n            *)\n              echo \"Unsupported architecture: $ARCH\" >&2\n              exit 1\n              ;;\n          esac\n          ARTIFACT=\"protoc-gen-grpc-web-${VERSION_NUMBER}-darwin-${ARCH_SUFFIX}\"\n          echo \"ARTIFACT=$ARTIFACT\" >> \"$GITHUB_ENV\"\n          echo \"artifact=$ARTIFACT\" >> \"$GITHUB_OUTPUT\"\n          echo \"Will produce artifact: $ARTIFACT\"\n      - name: Install Bazelisk (Bazel)\n        run: |\n          brew update\n          brew install bazelisk\n          bazelisk version\n      - name: Build protoc-gen-grpc-web with Bazel\n        run: |\n          bazelisk build //javascript/net/grpc/web/generator:protoc-gen-grpc-web\n      - name: Move artifact\n        run: |\n          mv bazel-bin/javascript/net/grpc/web/generator/protoc-gen-grpc-web \\\n            ./${ARTIFACT}\n      - name: Generate sha256\n        run: |\n          openssl dgst -sha256 -r -out ${ARTIFACT}.sha256 \\\n            ${ARTIFACT}\n      - name: Verify sha256\n        run: shasum -a 256 -c ${ARTIFACT}.sha256\n      - name: Upload artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: ${{ steps.meta.outputs.artifact }}\n          path: protoc-gen-grpc-web*\n"
  },
  {
    "path": ".github/workflows/make-plugin-windows.yml",
    "content": "name: Make Windows Plugin\n\non:\n  push:\n    paths:\n      - .github/workflows/make-plugin-windows.yml\n  pull_request:\n    paths:\n      - .github/workflows/make-plugin-windows.yml\n  workflow_dispatch:\n    inputs:\n      version_number:\n        description: 'Version number'\n        required: true\n        default: '2.x.x'\n\njobs:\n  build:\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [windows-2025, windows-11-arm]\n    runs-on: ${{ matrix.os }}\n    steps:\n      - uses: actions/checkout@v4\n      - name: Compute VERSION_NUMBER\n        run: |\n          INPUT_VERSION=\"${{ github.event.inputs.version_number }}\"\n          if [ -n \"$INPUT_VERSION\" ]; then\n            VERSION=\"$INPUT_VERSION\"\n          else\n            VERSION=\"$GITHUB_REF_NAME\"\n          fi\n          # Minimal sanitization: replace slashes with dashes to keep filenames valid\n          VERSION=\"${VERSION//\\//-}\"\n          echo \"VERSION_NUMBER=$VERSION\" >> \"$GITHUB_ENV\"\n          echo \"Computed VERSION_NUMBER=$VERSION\"\n        shell: bash\n      - name: Compute ARCH suffix and artifact name\n        id: meta\n        shell: powershell\n        run: |\n          $arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture\n          switch ($arch) {\n            'Arm64' { $archSuffix = 'aarch64' }\n            'X64'   { $archSuffix = 'x86_64' }\n            default { Write-Error \"Unsupported architecture: $arch\"; exit 1 }\n          }\n          $artifact = \"protoc-gen-grpc-web-$($env:VERSION_NUMBER)-windows-$archSuffix.exe\"\n          \"ARTIFACT=$artifact\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n          \"artifact=$artifact\" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append\n          Write-Host \"Will produce artifact: $artifact\"\n      - name: Install Bazelisk (Bazel)\n        shell: powershell\n        run: |\n          $arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture\n          switch ($arch) {\n            'Arm64' { $suffix = 'arm64' }\n            'X64'   { $suffix = 'amd64' }\n            default { Write-Error \"Unsupported architecture: $arch\"; exit 1 }\n          }\n          $url = \"https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-windows-$suffix.exe\"\n          $destDir = \"$env:RUNNER_TEMP\"\n          $dest = Join-Path $destDir 'bazelisk.exe'\n          Write-Host \"Downloading Bazelisk from $url to $dest\"\n          Invoke-WebRequest -UseBasicParsing -Uri $url -OutFile $dest\n          # Add to PATH for subsequent steps\n          $destDir | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append\n      - name: Print Bazelisk version\n        shell: powershell\n        run: bazelisk version\n      - name: Build protoc-gen-grpc-web with Bazel\n        run: bazelisk --noworkspace_rc --bazelrc=.bazelrc.windows build //javascript/net/grpc/web/generator:protoc-gen-grpc-web\n        shell: powershell\n      - name: Move artifact\n        run: |\n          mv bazel-bin/javascript/net/grpc/web/generator/protoc-gen-grpc-web.exe \"./${ARTIFACT}\"\n        shell: bash\n      - name: Generate sha256\n        run: |\n          openssl dgst -sha256 -r -out \"${ARTIFACT}.sha256\" \"${ARTIFACT}\"\n        shell: bash\n      - name: Verify sha256\n        shell: powershell\n        run: |\n          $shaFile = \"${env:ARTIFACT}.sha256\"\n          if (-not (Test-Path $shaFile)) { Write-Error \"SHA256 file not found: $shaFile\"; exit 1 }\n          $line = Get-Content -Raw $shaFile\n          if (-not $line) { Write-Error \"Empty sha256 file: $shaFile\"; exit 1 }\n          $expected = ($line -split '\\s+')[0].ToLower()\n          $actual = (Get-FileHash \"${env:ARTIFACT}\" -Algorithm SHA256).Hash.ToLower()\n          if ($actual -ne $expected) {\n            Write-Error \"SHA256 mismatch. Expected $expected, got $actual\"\n            exit 1\n          } else {\n            Write-Host \"SHA256 verified: $actual\"\n          }\n      - name: Upload artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: ${{ steps.meta.outputs.artifact }}\n          path: protoc-gen-grpc-web*\n"
  },
  {
    "path": ".github/workflows/release-source-archive.yml",
    "content": "name: Publish Stable Source Archive\n\non:\n  release:\n    types: [published]\n\njobs:\n  # Whenever a release is published, this uploads an accompanying stable source archive.\n  #\n  # Github doesn't guarantee stability of source archives for more than 6 months[1].\n  # More stability is required by projects like Bazel Central Registry[2][3].\n  #\n  # [1]: https://github.blog/open-source/git/update-on-the-future-stability-of-source-code-archives-and-hashes/\n  # [2]: https://github.com/bazelbuild/bazel-central-registry/blob/main/docs/README.md#validations\n  # [3]: https://blog.bazel.build/2023/02/15/github-archive-checksum.html\n  bazel-release-archive:\n    defaults:\n        run:\n          # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/\n          shell: /usr/bin/bash -euxo pipefail {0}\n    env:\n      # github.ref_name is defined here:\n      # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/accessing-contextual-information-about-workflow-runs#github-context\n      TAG: ${{github.ref_name}}\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    steps:\n      - uses: actions/checkout@v3\n      # GITHUB_REF is defined here:\n      # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables\n      - run: git archive --format zip    --prefix \"grpc-web-$TAG/\" --output \"grpc-web-source-${TAG}.zip\"    \"$GITHUB_REF\"\n      - run: git archive --format tar.gz --prefix \"grpc-web-$TAG/\" --output \"grpc-web-source-${TAG}.tar.gz\" \"$GITHUB_REF\"\n      - run: gh release upload \"${TAG}\" \"grpc-web-source-${TAG}.zip\" \"grpc-web-source-${TAG}.tar.gz\"\n        env:\n          GH_TOKEN: ${{ github.token }}\n"
  },
  {
    "path": ".gitignore",
    "content": ".vscode\nbazel-bin\nbazel-genfiles\nbazel-grpc-web\nbazel-out\nbazel-testlogs\n*.o\nprotoc-gen-*\n.DS_Store\ntarget\n.project\n.classpath\n.settings\nzig-out\nzig-cache\n.zig-cache\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"third_party/protobuf\"]\n\tpath = third_party/protobuf\n\turl = https://github.com/protocolbuffers/protobuf.git\n"
  },
  {
    "path": "AUTHORS",
    "content": "Google Inc.\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "[//]: # (GENERATED FILE -- DO NOT EDIT!)\n[//]: # (See scripts/release_notes.py for more details.)\n\n## 2.0.2\n\n- [#1507](https://github.com/grpc/grpc-web/pull/1507) Use regular enums for compatibility with TypeScript 5.9+\n\n## 2.0.1\n\n- [#1501](https://github.com/grpc/grpc-web/pull/1501) Update workflow to use Ubuntu 22.04 and static link libstdc++/libgcc\n\n## 2.0.0\n\n### Major Features\n\n- [#1490](https://github.com/grpc/grpc-web/pull/1490) Enable support for Editions in protoc-gen-grpc-web. @Quarke\n- [#1445](https://github.com/grpc/grpc-web/pull/1445) Upgrade protobuf to 27.1 and modernize codegen using new APIs @benjaminp\n\n### Other Changes\n\n- [#1496](https://github.com/grpc/grpc-web/pull/1496) Rework release workflows using Github runners (replacing Zig)\n- [#1494](https://github.com/grpc/grpc-web/pull/1494) Updates Closure compiler (`20250820.0.0`) and library\n- [#1463](https://github.com/grpc/grpc-web/pull/1463) fix: format of typescript definition @nnnnoel\n- [#1456](https://github.com/grpc/grpc-web/pull/1456) Bazel bzlmod support for grpc-web. @gonzojive\n- [#1452](https://github.com/grpc/grpc-web/pull/1452) Update protobuf-JS `3.14.0` -> `3.21.4`\n- [#1441](https://github.com/grpc/grpc-web/pull/1441) Upgrade to Bazel 6.5.0\n\n## 1.5.0\n\n- [#1369](https://github.com/grpc/grpc-web/pull/1369) (Typescript) Mark some `metadata` parameters as optional @andrewmbenton\n- [#1335](https://github.com/grpc/grpc-web/pull/1335) Update Debian (and other deps) and remove Java In-process Proxy\n- [#1334](https://github.com/grpc/grpc-web/pull/1334) Allow mixed-case headers\n- [#1330](https://github.com/grpc/grpc-web/pull/1330) Update ES6 .d.ts imports with comment about corresponding proto import... @gonzojive\n- [#1313](https://github.com/grpc/grpc-web/pull/1313) Update ES6 imports with comment about corresponding proto import path. @reddaly\n\n## 1.4.2\n\n- [#1289](https://github.com/grpc/grpc-web/pull/1289) Expose getName() in MethodDescriptor and fix TS definitions.\n- [#1230](https://github.com/grpc/grpc-web/pull/1230) GrpcWebClientReadableStream: keep falsy data @pro-wh\n\n## 1.4.1\n\n- [#1286](https://github.com/grpc/grpc-web/pull/1286) Fix duplicate dot in enum name (when \"package\" is specified)\n\n## 1.4.0\n\n### Major Features\n\n- [#1249](https://github.com/grpc/grpc-web/pull/1249) Use Zig to build aarch64 binaries @hronro\n- [#1203](https://github.com/grpc/grpc-web/pull/1203) Github Actions (workflows) for building `protoc-gen-grpc-web` plugins\n\n### Other Changes\n\n- [#1279](https://github.com/grpc/grpc-web/pull/1279) Fixes the status codes ordering in typescript definitions @chandraaditya\n- [#1278](https://github.com/grpc/grpc-web/pull/1278) Fix Enum with module in generated TS interface.\n- [#1254](https://github.com/grpc/grpc-web/pull/1254) Remove Trailing Slashes from Hostname @jkjk822\n- [#1252](https://github.com/grpc/grpc-web/pull/1252) Fix Zig setup step in CI @hronro\n- [#1231](https://github.com/grpc/grpc-web/pull/1231) Add version flag and version info in generated code @meling\n- [#1225](https://github.com/grpc/grpc-web/pull/1225) Improve error message & Internal code sync\n- [#1222](https://github.com/grpc/grpc-web/pull/1222) Update envoy version to 1.22 (with config updates) @tomk9\n- [#1211](https://github.com/grpc/grpc-web/pull/1211) Upgrade protobuf and grpc deps @aapeliv\n- [#1199](https://github.com/grpc/grpc-web/pull/1199) Revert \"Expose MethodDescriptor's public methods\"\n\n\n## 1.3.1\n\n- [#1184](https://github.com/grpc/grpc-web/pull/1184) Correctly support proto3 optional fields in commonjs+dts .d.ts output @mattnathan\n- [#1173](https://github.com/grpc/grpc-web/pull/1173) Update envoy version to 1.20\n- [#1172](https://github.com/grpc/grpc-web/pull/1172) Fix issue where **no RPC is issued when `deadline` is specified.**\n- [#1167](https://github.com/grpc/grpc-web/pull/1167) Fix missing TypeScript return type for `serverStreaming` calls. @lukasmoellerch\n- [#1166](https://github.com/grpc/grpc-web/pull/1166) Add missing exports from `RpcError` and add test.\n- [#1164](https://github.com/grpc/grpc-web/pull/1164) Add missing class exports @tinrab\n- [#1160](https://github.com/grpc/grpc-web/pull/1160) Expose MethodDescriptor's public methods @tomferreira\n\n## 1.3.0\n\n### Major Features\n\n- [#1139](https://github.com/grpc/grpc-web/pull/1139) Improve error type with `RpcError` & internal code sync (contributor: @TomiBelan)\n  + (experimental) Typescript users need to update type references from `Error` -> `RpcError`\n\n### Other Changes\n\n- [#1140](https://github.com/grpc/grpc-web/pull/1140) Improve `RpcError.code` typing & internal code sync (contributor:  @richieforeman)\n- [#1138](https://github.com/grpc/grpc-web/pull/1138) Remove Bazel in Javascript toolchain\n- [#1137](https://github.com/grpc/grpc-web/pull/1137) Revamp Closure JsUnit tests runtime and optimize test/build flows.\n- [#1115](https://github.com/grpc/grpc-web/pull/1115) Bump Bazel version -> 4.1.0 and Protobuf version -> 3.17.3\n- [#1107](https://github.com/grpc/grpc-web/pull/1107) Allow for custom install prefix @06kellyjac\n- [#1063](https://github.com/grpc/grpc-web/pull/1063) Also set timeout on HTTP request if deadline for grpc call is set @Yannic\n- [#1004](https://github.com/grpc/grpc-web/pull/1004) Bump closure library version to v20201102\n- [#1002](https://github.com/grpc/grpc-web/pull/1002) Bump Envoy version to 1.16.1\n- [#998](https://github.com/grpc/grpc-web/pull/998) Fix GrpcWebClientBaseOptions types in index.d.ts @acalvo\n- [#971](https://github.com/grpc/grpc-web/pull/971) Add grpc.web.ClientOptions to better document options and add type res... @jennnnny\n- [#969](https://github.com/grpc/grpc-web/pull/969) Fix non-determinism in code generator\n- [#941](https://github.com/grpc/grpc-web/pull/941) Fix Protobuf .d.ts typings for .proto files without package @Yannic\n\n\n## 1.2.1\n\n- [#910](https://github.com/grpc/grpc-web/pull/910) Add test to show how to access metadata in interceptor\n- [#903](https://github.com/grpc/grpc-web/pull/903) Add error handling to a few error conditions\n- [#886](https://github.com/grpc/grpc-web/pull/886) Add missing types definitions\n- [#885](https://github.com/grpc/grpc-web/pull/885) Bump Envoy to 1.15.0\n- [#884](https://github.com/grpc/grpc-web/pull/884) Update protoc plugin to support Proto3 optional\n- [#882](https://github.com/grpc/grpc-web/pull/882) Add @interface MethodDescroptorInterface [@Jennnnny](https://github.com/Jennnnny)\n- [#880](https://github.com/grpc/grpc-web/pull/880) Update Bazel to 3.3.1 [@Yannic](https://github.com/Yannic)\n- [#874](https://github.com/grpc/grpc-web/pull/874) Add removeListener and missing metadata event types [@danielthank](https://github.com/danielthank)\n- [#872](https://github.com/grpc/grpc-web/pull/872) [bazel] Introduce grpc_web_toolchain [@Yannic](https://github.com/Yannic)\n- [#871](https://github.com/grpc/grpc-web/pull/871) [generator] Refactor dependency management [@Yannic](https://github.com/Yannic)\n- [#869](https://github.com/grpc/grpc-web/pull/869) Add scripts to run interop-tests on grpc-web Java connector\n\n\n## 1.2.0\n\n### Major Features\n\n- [#847](https://github.com/grpc/grpc-web/pull/847) Allow multiple .on() callbacks and fix issue with non-OK status\n\n### Other Changes\n\n- [#859](https://github.com/grpc/grpc-web/pull/859) Fix envoy.yaml deprecated fields [@dmaixner](https://github.com/dmaixner)\n- [#858](https://github.com/grpc/grpc-web/pull/858) Refactor error handling in grpcwebclientbase\n- [#857](https://github.com/grpc/grpc-web/pull/857) Migrate to ES6 classes\n- [#852](https://github.com/grpc/grpc-web/pull/852) Update to use @grpc/grpc-js node package, and update helloworld exampl...\n- [#851](https://github.com/grpc/grpc-web/pull/851) Add a ThenableCall base class for the promise-based unaryCall function [@Jennnnny](https://github.com/Jennnnny)\n- [#844](https://github.com/grpc/grpc-web/pull/844) Fix code generator bug and add tests\n- [#833](https://github.com/grpc/grpc-web/pull/833) Add proper author attribution to release notes / changelog\n- [#827](https://github.com/grpc/grpc-web/pull/827) Splitting callback based client and Promise based client into multiple... [@Jennnnny](https://github.com/Jennnnny)\n- [#822](https://github.com/grpc/grpc-web/pull/822) use explicit envoy release tag [@xsbchen](https://github.com/xsbchen)\n- [#821](https://github.com/grpc/grpc-web/pull/821) Experimental Feature: Add ES6 import style [@Yannic](https://github.com/Yannic)\n- [#738](https://github.com/grpc/grpc-web/pull/738) Avoid double slash in url when client hostname has tailing slash [@hanabi1224](https://github.com/hanabi1224)\n\n\n## 1.1.0\n\n### Major Features\n\n- [#785](https://github.com/grpc/grpc-web/pull/785) grpc-web interceptors implementation [@Jennnnny](https://github.com/Jennnnny)\n- [#772](https://github.com/grpc/grpc-web/pull/772) Add interop test spec and interop tests\n\n### Other Changes\n\n- [#818](https://github.com/grpc/grpc-web/pull/818) All java connector interop tests are passing now\n- [#804](https://github.com/grpc/grpc-web/pull/804) Fix a bug in test: callback not properly intercepted\n- [#801](https://github.com/grpc/grpc-web/pull/801) Trying to speed up tests\n- [#797](https://github.com/grpc/grpc-web/pull/797) Split basic tests with interop tests\n- [#780](https://github.com/grpc/grpc-web/pull/780) Add missing separator to imports from external files [@tomiaijo](https://github.com/tomiaijo)\n- [#777](https://github.com/grpc/grpc-web/pull/777) Add .on(metadata,...) callback to distinguish initial metadata\n- [#764](https://github.com/grpc/grpc-web/pull/764) [generator] Move options parsing into dedicated class [@Yannic](https://github.com/Yannic)\n- [#761](https://github.com/grpc/grpc-web/pull/761) Update generic client [@Jennnnny](https://github.com/Jennnnny)\n- [#756](https://github.com/grpc/grpc-web/pull/756) Add eval test for TypeScript generated code\n- [#752](https://github.com/grpc/grpc-web/pull/752) Disable static checkers on generated js files [@IagoLast](https://github.com/IagoLast)\n- [#747](https://github.com/grpc/grpc-web/pull/747) Enable builder pattern in Typescript protobuf messages. [@Orphis](https://github.com/Orphis)\n- [#746](https://github.com/grpc/grpc-web/pull/746) Generate Promise based overloads for unary calls in Typescript [@Orphis](https://github.com/Orphis)\n- [#745](https://github.com/grpc/grpc-web/pull/745) [bazel] Update rules_closure + fix linter warnings [@Yannic](https://github.com/Yannic)\n- [#734](https://github.com/grpc/grpc-web/pull/734) Allow GrpcWebStreamParser to accept Uint8Array [@travikk](https://github.com/travikk)\n- [#723](https://github.com/grpc/grpc-web/pull/723) Update bazel version\n- [#720](https://github.com/grpc/grpc-web/pull/720) Fix grpcwebproxy interop\n- [#716](https://github.com/grpc/grpc-web/pull/716) allow_origin is deprecated in latest envoy server [@noconnor](https://github.com/noconnor)\n- [#695](https://github.com/grpc/grpc-web/pull/695) Fix issue 632 (double execution of callback) [@hfinger](https://github.com/hfinger)\n- [#692](https://github.com/grpc/grpc-web/pull/692) Do not hardcode CXX to g++\n\n\n## 1.0.7\n\n- [#671](https://github.com/grpc/grpc-web/pull/671) Add metadata to error callback\n- [#668](https://github.com/grpc/grpc-web/pull/668) Remove stream_body.proto\n- [#665](https://github.com/grpc/grpc-web/pull/665) Add config for Bazel CI [@Yannic](https://github.com/Yannic)\n- [#663](https://github.com/grpc/grpc-web/pull/663) nginx example Expose-Headers add Grpc-Message,Grpc-Status [@zsluedem](https://github.com/zsluedem)\n- [#657](https://github.com/grpc/grpc-web/pull/657) Ensure that the end callback is called [@vbfox](https://github.com/vbfox)\n- [#655](https://github.com/grpc/grpc-web/pull/655) Use closure compiler from npm in build.js [@vbfox](https://github.com/vbfox)\n- [#654](https://github.com/grpc/grpc-web/pull/654) Ignore MacOS .DS_Store files [@vbfox](https://github.com/vbfox)\n- [#652](https://github.com/grpc/grpc-web/pull/652) Fix error callback\n- [#644](https://github.com/grpc/grpc-web/pull/644) Add CallOptions class [@Jennnnny](https://github.com/Jennnnny)\n- [#641](https://github.com/grpc/grpc-web/pull/641) Add/update GOVERNANCE.md and CONTRIBUTING.md\n- [#635](https://github.com/grpc/grpc-web/pull/635) Fix generated code return type, and remove unused var\n- [#628](https://github.com/grpc/grpc-web/pull/628) Added API for simple unary call [@Jennnnny](https://github.com/Jennnnny)\n- [#621](https://github.com/grpc/grpc-web/pull/621) Fix output directory name when using import_style=typescript [@asv](https://github.com/asv)\n- [#619](https://github.com/grpc/grpc-web/pull/619) Return specific grpc status code on http error [@harmangakhal](https://github.com/harmangakhal)\n- [#618](https://github.com/grpc/grpc-web/pull/618) Generate method descriptors into multiple files [@Jennnnny](https://github.com/Jennnnny)\n- [#617](https://github.com/grpc/grpc-web/pull/617) Remove `enabled` deprecated field [@gsalisi](https://github.com/gsalisi)\n- [#615](https://github.com/grpc/grpc-web/pull/615) Add support in code generator for printing only method descriptors [@Jennnnny](https://github.com/Jennnnny)\n- [#608](https://github.com/grpc/grpc-web/pull/608) Fix status and error callbacks\n\n\n## 1.0.6\n\n- [#604](https://github.com/grpc/grpc-web/pull/604) Add option to set withCredentials to true\n- [#603](https://github.com/grpc/grpc-web/pull/603) Adding some groundwork for generic client [@Jennnnny](https://github.com/Jennnnny)\n- [#600](https://github.com/grpc/grpc-web/pull/600) Add generated code eval test\n- [#599](https://github.com/grpc/grpc-web/pull/599) fix wrong package name of input type [@lqs](https://github.com/lqs)\n- [#593](https://github.com/grpc/grpc-web/pull/593) Fix: Helloworld Example - Enabled Deprecation [@gary-lo](https://github.com/gary-lo)\n\n\n## 1.0.5\n\n- [#582](https://github.com/grpc/grpc-web/pull/582) Ensure credentials are not undefined in typescript [@Globegitter](https://github.com/Globegitter)\n- [#579](https://github.com/grpc/grpc-web/pull/579) Uppercase enum keys in TypeScript definitions [@benfoxbotica](https://github.com/benfoxbotica)\n- [#578](https://github.com/grpc/grpc-web/pull/578) Fix depset issues with/upgrade to Bazel 0.27.1 [@factuno-db](https://github.com/factuno-db)\n- [#567](https://github.com/grpc/grpc-web/pull/567) Introducing MethodDescriptor [@Jennnnny](https://github.com/Jennnnny)\n- [#559](https://github.com/grpc/grpc-web/pull/559) Adding new fields to MethodInfo [@Jennnnny](https://github.com/Jennnnny)\n- [#556](https://github.com/grpc/grpc-web/pull/556) Add fix for deadline of strings, NaN, Infinity and -Infinity [@CatEars](https://github.com/CatEars)\n- [#546](https://github.com/grpc/grpc-web/pull/546) Changes to deserializeBinary API\n- [#540](https://github.com/grpc/grpc-web/pull/540) Method Derserializer should take Uint8Array [@pnegahdar](https://github.com/pnegahdar)\n- [#519](https://github.com/grpc/grpc-web/pull/519) remove duplicated has$field$ method for oneof [@yangjian](https://github.com/yangjian)\n- [#512](https://github.com/grpc/grpc-web/pull/512) Make client args `credentials` and `options` optional [@jonahbron](https://github.com/jonahbron)\n\n\n## 1.0.4\n\n- [#502](https://github.com/grpc/grpc-web/pull/502) Attempt to fix flakiness of 'bazel test' [@Yannic](https://github.com/Yannic)\n- [#497](https://github.com/grpc/grpc-web/pull/497) Remove a return that skip emission of end callback [@tinou98](https://github.com/tinou98)\n- [#494](https://github.com/grpc/grpc-web/pull/494) [bazel] Migrate protobuf info provider to new-style one [@Yannic](https://github.com/Yannic)\n- [#482](https://github.com/grpc/grpc-web/pull/482) feature: Typings codegen for bytes field type [@shaxbee](https://github.com/shaxbee)\n- [#481](https://github.com/grpc/grpc-web/pull/481) Add module alias to enums for Typescript [@rogchap](https://github.com/rogchap)\n- [#460](https://github.com/grpc/grpc-web/pull/460) add typescript definition for Oneof fields [@yangjian](https://github.com/yangjian)\n- [#452](https://github.com/grpc/grpc-web/pull/452) fix: exclude map entry message from typings, fix optional values [@shaxbee](https://github.com/shaxbee)\n- [#448](https://github.com/grpc/grpc-web/pull/448) Export Map types correctly, optional getter/setters for message types [@shaxbee](https://github.com/shaxbee)\n- [#444](https://github.com/grpc/grpc-web/pull/444) feature: Messages in typings extending jspb.Message [@shaxbee](https://github.com/shaxbee)\n- [#433](https://github.com/grpc/grpc-web/pull/433) Match name nesting and imports in .d.ts with .js files [@shaxbee](https://github.com/shaxbee)\n- [#430](https://github.com/grpc/grpc-web/pull/430) Use camelCase in AsObject definition [@johanbrandhorst](https://github.com/johanbrandhorst)\n- [#429](https://github.com/grpc/grpc-web/pull/429) Fix type error in serverStreaming method [@johanbrandhorst](https://github.com/johanbrandhorst)\n- [#427](https://github.com/grpc/grpc-web/pull/427) Promise function should use ES5 functions rather than fat arrows (IE b... [@rogchap](https://github.com/rogchap)\n- [#422](https://github.com/grpc/grpc-web/pull/422) Enable ADVANCED_OPTIMIZATIONS in Closure Compiler [@jjbubudi](https://github.com/jjbubudi)\n- [#421](https://github.com/grpc/grpc-web/pull/421) [bazel] Upgrade to 0.22.0 [@Yannic](https://github.com/Yannic)\n- [#413](https://github.com/grpc/grpc-web/pull/413) Emit status event on empty stream response [@shaxbee](https://github.com/shaxbee)\n- [#409](https://github.com/grpc/grpc-web/pull/409) Fix metadata typings for TS client [@bpicolo](https://github.com/bpicolo)\n- [#404](https://github.com/grpc/grpc-web/pull/404) Generate Typescript definition for top level Enums [@rogchap](https://github.com/rogchap)\n\n\n## 1.0.3\n\n- [#391](https://github.com/grpc/grpc-web/pull/391) A script to compile protoc plugin\n- [#385](https://github.com/grpc/grpc-web/pull/385) Codegen: Support nested types and enums [@shaxbee](https://github.com/shaxbee)\n- [#368](https://github.com/grpc/grpc-web/pull/368) Make the bazel rules work with current rules_closure. [@factuno-db](https://github.com/factuno-db)\n- [#367](https://github.com/grpc/grpc-web/pull/367) update examples to use addService [@mitchdraft](https://github.com/mitchdraft)\n- [#365](https://github.com/grpc/grpc-web/pull/365) Fix response header value with colon\n- [#362](https://github.com/grpc/grpc-web/pull/362) Fix the method name clashes for generated commonjs files  [@weilip1803](https://github.com/weilip1803)\n- [#360](https://github.com/grpc/grpc-web/pull/360) Fix the import path for generated typescript files [@at-ishikawa](https://github.com/at-ishikawa)\n\n\n## 1.0.2\n\n\n## 1.0.1\n\n- [#354](https://github.com/grpc/grpc-web/pull/354) [dts] Generate PromiseClient type definitions in d.ts file [@at-ishikawa](https://github.com/at-ishikawa)\n- [#352](https://github.com/grpc/grpc-web/pull/352)  Add a max grpc timeout to the echo example.  [@mjduijn](https://github.com/mjduijn)\n- [#348](https://github.com/grpc/grpc-web/pull/348) Fix output dts about 'repeated' for --grpc-web_out=import_style=common... [@rybbchao](https://github.com/rybbchao)\n- [#345](https://github.com/grpc/grpc-web/pull/345) update typescript generation to work in strict mode [@henriiik](https://github.com/henriiik)\n- [#330](https://github.com/grpc/grpc-web/pull/330) Use official rules_closure repository [@Yannic](https://github.com/Yannic)\n\n\n## 1.0.0\n\n- [#314](https://github.com/grpc/grpc-web/pull/314) Add a unit test for proto with no package\n- [#313](https://github.com/grpc/grpc-web/pull/313) Show how deadline can be set\n- [#311](https://github.com/grpc/grpc-web/pull/311) Document how to prevent Envoy to timeout streaming [@mitar](https://github.com/mitar)\n- [#310](https://github.com/grpc/grpc-web/pull/310) Correctly generate code if package name is empty [@mitar](https://github.com/mitar)\n- [#304](https://github.com/grpc/grpc-web/pull/304) Add a simple Hello World Guide\n- [#303](https://github.com/grpc/grpc-web/pull/303) Error code should be number\n- [#276](https://github.com/grpc/grpc-web/pull/276) Fix plugin compile error\n- [#272](https://github.com/grpc/grpc-web/pull/272) Fix cpp warnings\n\n\n## 0.4.0\n\n- [#263](https://github.com/grpc/grpc-web/pull/263) Make \"Quick\" start quicker\n- [#258](https://github.com/grpc/grpc-web/pull/258) Experimental Typescript support\n- [#257](https://github.com/grpc/grpc-web/pull/257) Fix bug with button in example\n\n\n## 0.3.0\n\n- [#249](https://github.com/grpc/grpc-web/pull/249) Various fixes to codegen plugin\n- [#247](https://github.com/grpc/grpc-web/pull/247) Add generated code unit test\n- [#240](https://github.com/grpc/grpc-web/pull/240) webpack demo\n- [#239](https://github.com/grpc/grpc-web/pull/239) Expose response metadata for unary calls\n- [#219](https://github.com/grpc/grpc-web/pull/219) Add bazel rule closure_grpc_web_library [@Yannic](https://github.com/Yannic)\n- [#217](https://github.com/grpc/grpc-web/pull/217) Added multiple proxies interoperability\n\n\n## 0.2.0\n\n- [#212](https://github.com/grpc/grpc-web/pull/212) Added commonjs-example Dockerfile\n- [#211](https://github.com/grpc/grpc-web/pull/211) commonjs support with import_style option [@zaucy](https://github.com/zaucy)\n- [#210](https://github.com/grpc/grpc-web/pull/210) grpcweb npm runtime module [@zaucy](https://github.com/zaucy)\n- [#209](https://github.com/grpc/grpc-web/pull/209) Add bazel integration and tests\n- [#206](https://github.com/grpc/grpc-web/pull/206) Surface underlying XHR errors better\n- [#185](https://github.com/grpc/grpc-web/pull/185) Support for proto files without packages [@zaucy](https://github.com/zaucy)\n"
  },
  {
    "path": "CODE-OF-CONDUCT.md",
    "content": "## Community Code of Conduct\n\ngRPC-Web follows the\n[CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to contribute\n\nWe definitely welcome patches and contribution to gRPC-Web! Here is some guideline\nand information about how to do so.\n\nPlease read the gRPC\norganization's [governance rules](https://github.com/grpc/grpc-community/blob/master/governance.md)\nand [contribution guidelines](https://github.com/grpc/grpc-community/blob/master/CONTRIBUTING.md) before proceeding.\n\n## Getting started\n\n### Legal requirements\n\nIn order to protect both you and ourselves, you will need to sign the\n[Contributor License Agreement](https://cla.developers.google.com/clas).\n\n### Technical requirements\n\nThe basic build script should run to completion.\n\n```sh\n$ ./scripts/kokoro.sh\n```\n\nMore details to come.\n"
  },
  {
    "path": "GOVERNANCE.md",
    "content": "This repository is governed by the gRPC organization's [governance rules](https://github.com/grpc/grpc-community/blob/master/governance.md).\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "MAINTAINERS.md",
    "content": "This page lists all active maintainers of this repository. If you were a\nmaintainer and would like to add your name to the Emeritus list, please send us a\nPR.\n\nSee [GOVERNANCE.md](https://github.com/grpc/grpc-community/blob/master/governance.md)\nfor governance guidelines and how to become a maintainer.\nSee [CONTRIBUTING.md](https://github.com/grpc/grpc-community/blob/master/CONTRIBUTING.md)\nfor general contribution guidelines.\n\n## Maintainers (in alphabetical order)\n- [sampajano](https://github.com/sampajano), Google Inc.\n- [wenbozhu](https://github.com/wenbozhu), Google Inc.\n\n## Emeritus Maintainers (in alphabetical order)\n- [fengli79](https://github.com/fengli79)\n- [stanley-cheung](https://github.com/stanley-cheung)\n"
  },
  {
    "path": "MODULE.bazel",
    "content": "\"\"\"\nA bazel module for the grpc-web project.\n\nVisit https://grpc.io/ and https://github.com/grpc/grpc-web for\nmore information about the project.\n\"\"\"\n\nmodule(\n    name = \"grpc-web\",\n    version = \"1.6.0\",\n    compatibility_level = 1,\n    repo_name = \"com_github_grpc_grpc_web\",\n)\n\nbazel_dep(name = \"protobuf\", version = \"27.1\", repo_name = \"com_google_protobuf\")\nbazel_dep(name = \"grpc\", version = \"1.65.0\", repo_name = \"com_github_grpc_grpc\")\nbazel_dep(name = \"rules_cc\", version = \"0.0.2\")\nbazel_dep(name = \"rules_proto\", version = \"6.0.2\")\n\n# Needed to resolve https://github.com/bazelbuild/bazel-central-registry/issues/2538.\nsingle_version_override(\n    module_name = \"grpc-java\",\n    version = \"1.64.0\",\n)\n"
  },
  {
    "path": "Makefile",
    "content": "ROOT_DIR := $(shell pwd)\n\nall: clean\n\nplugin:\n\tcd \"$(ROOT_DIR)\"/javascript/net/grpc/web/generator && make\n\ninstall-plugin:\n\tcd \"$(ROOT_DIR)\"/javascript/net/grpc/web/generator && make install\n\nclean:\n\tcd \"$(ROOT_DIR)\"/javascript/net/grpc/web/generator && make clean\n\tcd \"$(ROOT_DIR)\"\n"
  },
  {
    "path": "PATENTS",
    "content": "Additional IP Rights Grant (Patents)\n\n\"This implementation\" means the copyrightable works distributed by\nGoogle as part of the GRPC project.\n\nGoogle hereby grants to You a perpetual, worldwide, non-exclusive,\nno-charge, royalty-free, irrevocable (except as stated in this section)\npatent license to make, have made, use, offer to sell, sell, import,\ntransfer and otherwise run, modify and propagate the contents of this\nimplementation of GRPC, where such license applies only to those patent\nclaims, both currently owned or controlled by Google and acquired in\nthe future, licensable by Google that are necessarily infringed by this\nimplementation of GRPC.  This grant does not include claims that would be\ninfringed only as a consequence of further modification of this\nimplementation.  If you or your agent or exclusive licensee institute or\norder or agree to the institution of patent litigation against any\nentity (including a cross-claim or counterclaim in a lawsuit) alleging\nthat this implementation of GRPC or any code incorporated within this\nimplementation of GRPC constitutes direct or contributory patent\ninfringement, or inducement of patent infringement, then any patent\nrights granted to you under this License for this implementation of GRPC\nshall terminate as of the date such litigation is filed.\n"
  },
  {
    "path": "README.md",
    "content": "# gRPC Web &middot; [![npm version](https://img.shields.io/npm/v/grpc-web.svg?style=flat)](https://www.npmjs.com/package/grpc-web)\n\nA JavaScript implementation of [gRPC][] for browser clients. For more information,\nincluding a **quick start**, see the [gRPC-web documentation][grpc-web-docs].\n\ngRPC-web clients connect to gRPC services via a special proxy; by default,\ngRPC-web uses [Envoy][].\n\nIn the future, we expect gRPC-web to be supported in language-specific web\nframeworks for languages such as Python, Java, and Node. For details, see the\n[roadmap](doc/roadmap.md).\n\n## Streaming Support\ngRPC-web currently supports 2 RPC modes:\n- Unary RPCs ([example](#make-a-unary-rpc-call))\n- Server-side Streaming RPCs ([example](#server-side-streaming)) (NOTE: Only when [`grpcwebtext`](#wire-format-mode) mode is used.)\n\nClient-side and Bi-directional streaming is not currently supported (see [streaming roadmap](doc/streaming-roadmap.md)).\n\n## Quick Start\n\nEager to get started? Try the [Hello World example][]. From this example, you'll\nlearn how to do the following:\n\n - Define your service using protocol buffers\n - Implement a simple gRPC Service using Node.js\n - Configure the Envoy proxy\n - Generate protobuf message classes and client service stub for the client\n - Compile all the JS dependencies into a static library that can be consumed\n   by the browser easily\n\n## Advanced Demo: Browser Echo App\n\nYou can also try to run a more advanced Echo app from the browser with a\nstreaming example.\n\nFrom the repo root directory:\n\n```sh\n$ docker-compose pull prereqs node-server envoy commonjs-client\n$ docker-compose up node-server envoy commonjs-client\n```\n\nOpen a browser tab, and visit http://localhost:8081/echotest.html.\n\nTo shutdown: `docker-compose down`.\n\n## Runtime Library\n\nThe gRPC-web runtime library is available on npm:\n\n```sh\n$ npm i grpc-web\n```\n\n## Code Generator Plugins\n\n### (Prerequisite) 1. Protobuf (`protoc`)\n\nIf you don't already have [`protoc`](https://github.com/protocolbuffers/protobuf)\ninstalled, download it first from [here](https://github.com/protocolbuffers/protobuf/releases) and install it on your PATH.\n\nIf you use Homebrew (on macOS), you could run:\n\n```sh\nbrew install protobuf\n```\n\n### (Prerequisite) 2. Protobuf-javascript (`protoc-gen-js`)\n\nIf you don't have [`protoc-gen-js`](https://github.com/protocolbuffers/protobuf-javascript) installed, download it from [protocolbuffers/protobuf-javascript](https://github.com/protocolbuffers/protobuf-javascript/releases) and install it on your PATH.\n\nOr, use the [third-party](https://www.npmjs.com/package/protoc-gen-js) npm installer:\n\n```\nnpm install -g protoc-gen-js\n```\n\n### 3. Install gRPC-Web Code Generator\n\nYou can download the `protoc-gen-grpc-web` protoc plugin from our\n[release](https://github.com/grpc/grpc-web/releases) page:\n\nMake sure all executables are discoverable from your PATH.\n\nFor example, on macOS, you can do:\n\n```sh\nsudo mv protoc-gen-grpc-web-2.0.2-darwin-aarch64 \\\n    /usr/local/bin/protoc-gen-grpc-web\n\nchmod +x /usr/local/bin/protoc-gen-grpc-web\n```\n\nNote: If you are using our Docker setup, the `prereqs` image already includes\nboth `protoc` and the `protoc-gen-grpc-web` plugin on the PATH.\n\n### (Optional) 4. Verify Installations\n\nYou can optionally verify the plugins work by following our [Hello World example](https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway/examples/helloworld#generating-stubs):\n\n```sh\ncd net/grpc/gateway/examples/helloworld\n\nprotoc -I=. helloworld.proto \\\n  --js_out=import_style=commonjs:. \\\n  --grpc-web_out=import_style=commonjs,mode=grpcwebtext:.\n```\n\nAfter the command runs successfully, you should now see two new files generated\nin the current directory. By running:\n\n```\nls -1 *_pb.js\n```\n\nInstallation is successful if you see the following 2 files:\n\n - `helloworld_pb.js` — Generated by `protoc-gen-js` plugin\n - `helloworld_grpc_web_pb.js` - Generated by gRPC-Web plugin\n\n## Client Configuration Options\n\nTypically, you will run the following command to generate the proto messages\nand the service client stub from your `.proto` definitions:\n\n```sh\nprotoc -I=$DIR echo.proto \\\n  --js_out=import_style=commonjs:$OUT_DIR \\\n  --grpc-web_out=import_style=commonjs,mode=grpcwebtext:$OUT_DIR\n```\n\nYou can then use Browserify, Webpack, Closure Compiler, etc. to resolve imports\nat compile time.\n\n### Import Style\n\n`import_style=closure`: The default generated code has\n[Closure](https://developers.google.com/closure/library/) `goog.require()`\nimport style.\n\n`import_style=commonjs`: The\n[CommonJS](https://requirejs.org/docs/commonjs.html) style `require()` is\nalso supported.\n\n`import_style=commonjs+dts`: (Experimental) In addition to above, a `.d.ts`\ntypings file will also be generated for the protobuf messages and service stub.\n\n`import_style=typescript`: (Experimental) The service stub will be generated\nin TypeScript. See **TypeScript Support** below for information on how to\ngenerate TypeScript files.\n\n> **Note:** The `commonjs+dts` and `typescript` styles are only supported by\n`--grpc-web_out=import_style=...`, not by `--js_out=import_style=...`.\n\n### Wire Format Mode\n\nFor more information about the gRPC-web wire format, see the\n[specification](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2).\n\n`mode=grpcwebtext`: The default generated code sends the payloads in the\n`grpc-web-text` format.\n\n  - `Content-Type: application/grpc-web-text`\n  - Payloads are base64-encoded.\n  - Both unary and server streaming calls are supported.\n\n`mode=grpcweb`: A binary protobuf format is also supported.\n\n  - `Content-Type: application/grpc-web+proto`\n  - Payloads are in the binary protobuf format.\n  - Only unary calls are supported.\n\n## How It Works\n\nLet's take a look at how gRPC-web works with a simple example. You can find out\nhow to build, run and explore the example yourself in\n[Build and Run the Echo Example](net/grpc/gateway/examples/echo).\n\n### 1. Define your service\n\nThe first step when creating any gRPC service is to define it. Like all gRPC\nservices, gRPC-web uses\n[protocol buffers](https://developers.google.com/protocol-buffers) to define\nits RPC service methods and their message request and response types.\n\n```protobuf\nmessage EchoRequest {\n  string message = 1;\n}\n\n...\n\nservice EchoService {\n  rpc Echo(EchoRequest) returns (EchoResponse);\n\n  rpc ServerStreamingEcho(ServerStreamingEchoRequest)\n      returns (stream ServerStreamingEchoResponse);\n}\n```\n\n### 2. Run the server and proxy\n\nNext you need to have a gRPC server that implements the service interface and a\ngateway proxy that allows the client to connect to the server. Our example\nbuilds a simple Node gRPC backend server and the Envoy proxy.\n\nFor the Echo service: see the\n[service implementation](net/grpc/gateway/examples/echo/node-server/server.js).\n\nFor the Envoy proxy: see the\n[config YAML file](net/grpc/gateway/examples/echo/envoy.yaml).\n\n### 3. Write your JS client\n\nOnce the server and gateway are up and running, you can start making gRPC calls\nfrom the browser!\n\nCreate your client:\n\n```js\nvar echoService = new proto.mypackage.EchoServiceClient(\n  'http://localhost:8080');\n```\n\n#### Make a unary RPC call:\n\n```js\nvar request = new proto.mypackage.EchoRequest();\nrequest.setMessage(msg);\nvar metadata = {'custom-header-1': 'value1'};\nechoService.echo(request, metadata, function(err, response) {\n  if (err) {\n    console.log(err.code);\n    console.log(err.message);\n  } else {\n    console.log(response.getMessage());\n  }\n});\n```\n\n#### Server-side streaming:\n\n```js\nvar stream = echoService.serverStreamingEcho(streamRequest, metadata);\nstream.on('data', function(response) {\n  console.log(response.getMessage());\n});\nstream.on('status', function(status) {\n  console.log(status.code);\n  console.log(status.details);\n  console.log(status.metadata);\n});\nstream.on('end', function(end) {\n  // stream end signal\n});\n\n// to close the stream\nstream.cancel();\n```\n\nFor an in-depth tutorial, see [this\npage](net/grpc/gateway/examples/echo/tutorial.md).\n\n## Setting a Deadline\n\nYou can set a deadline for your RPC by setting a `deadline` header. The value\nshould be a Unix timestamp, in milliseconds.\n\n```js\nvar deadline = new Date();\ndeadline.setSeconds(deadline.getSeconds() + 1);\n\nclient.sayHelloAfterDelay(request, {deadline: deadline.getTime().toString()},\n  (err, response) => {\n    // err will be populated if the RPC exceeds the deadline\n    ...\n  });\n```\n\n## TypeScript Support\n\nThe `grpc-web` module can now be imported as a TypeScript module. This is\ncurrently an experimental feature. Any feedback welcome!\n\nWhen using the `protoc-gen-grpc-web` protoc plugin, mentioned above, pass in\neither:\n\n - `import_style=commonjs+dts`: existing CommonJS style stub + `.d.ts` typings\n - `import_style=typescript`: full TypeScript output\n\nDo *not* use `import_style=typescript` for `--js_out`, it will silently be\nignored. Instead you should use `--js_out=import_style=commonjs`, or\n`--js_out=import_style=commonjs,binary` if you are using `mode=grpcweb`. The\n`--js_out` plugin will generate JavaScript code (`echo_pb.js`), and the\n`-grpc-web_out` plugin will generate a TypeScript definition file for it\n(`echo_pb.d.ts`). This is a temporary hack until the `--js_out` supports\nTypeScript itself.\n\nFor example, this is the command you should use to generate TypeScript code\nusing the binary wire format:\n\n```sh\nprotoc -I=$DIR echo.proto \\\n  --js_out=import_style=commonjs,binary:$OUT_DIR \\\n  --grpc-web_out=import_style=typescript,mode=grpcweb:$OUT_DIR\n```\n\nIt will generate the following files:\n\n* `EchoServiceClientPb.ts` - Generated by `--grpc-web_out`, contains the\nTypeScript gRPC-web code.\n* `echo_pb.js` - Generated by `--js_out`, contains the JavaScript Protobuf\ncode.\n* `echo_pb.d.ts` - Generated by `--grpc-web_out`, contains TypeScript\ndefinitions for `echo_pb.js`.\n\n### Using Callbacks\n\n```ts\nimport * as grpcWeb from 'grpc-web';\nimport {EchoServiceClient} from './EchoServiceClientPb';\nimport {EchoRequest, EchoResponse} from './echo_pb';\n\nconst echoService = new EchoServiceClient('http://localhost:8080', null, null);\n\nconst request = new EchoRequest();\nrequest.setMessage('Hello World!');\n\nconst call = echoService.echo(request, {'custom-header-1': 'value1'},\n  (err: grpcWeb.RpcError, response: EchoResponse) => {\n    console.log(response.getMessage());\n  });\ncall.on('status', (status: grpcWeb.Status) => {\n  // ...\n});\n```\n\n(See [here](https://github.com/grpc/grpc-web/blob/4d7dc44c2df522376394d3e3315b7ab0e010b0c5/packages/grpc-web/index.d.ts#L29-L39) for the full list of possible `.on(...)` callbacks.)\n\n### (Optional) Using Promises (Limited Features)\n\n> **NOTE:** It is not possible to access the `.on(...)` callbacks (e.g. for `metadata` and `status`) when Promise is used.\n\n```ts\n// Create a Promise client instead\nconst echoService = new EchoServicePromiseClient('http://localhost:8080', null, null);\n\n... (same as above)\n\nthis.echoService.echo(request, {'custom-header-1': 'value1'})\n  .then((response: EchoResponse) => {\n    console.log(`Received response: ${response.getMessage()}`);\n  }).catch((err: grpcWeb.RpcError) => {\n    console.log(`Received error: ${err.code}, ${err.message}`);\n  });\n```\n\nFor the full TypeScript example, see\n[ts-example/client.ts](net/grpc/gateway/examples/echo/ts-example/client.ts) and the [instructions](net/grpc/gateway/examples/echo/ts-example) to run.\n\n## Custom Interceptors\n\nCustom interceptors can be implemented and chained, which could be useful for features like auth, retries, etc.\n\nThere are 2 types of interceptors ([interfaces](https://github.com/grpc/grpc-web/blob/3cd7e0d43493d4694fed78400e4ad78031d70c09/packages/grpc-web/index.d.ts#L55-L65)):\n\n- `UnaryInterceptor` ([doc](https://grpc.io/blog/grpc-web-interceptor/#stream-interceptor-example), [example](https://github.com/grpc/grpc-web/blob/master/packages/grpc-web/test/tsc-tests/client04.ts)) - Intercept Unary RPCs; can only be used with Promise clients.\n- `StreamInterceptor` ([doc](https://grpc.io/blog/grpc-web-interceptor/#stream-interceptor-example), [example](https://github.com/grpc/grpc-web/blob/master/packages/grpc-web/test/tsc-tests/client03.ts)) - More versatile; can be used with regular clients.\n\nFor more details, see [this blog post](https://grpc.io/blog/grpc-web-interceptor/).\n\n\n## Ecosystem\n\n### Proxy Interoperability\n\nMultiple proxies support the gRPC-web protocol.\n\n1. The current **default proxy** is [Envoy][], which supports gRPC-web out of the box.\n\n\t```sh\n\t$ docker-compose up -d node-server envoy commonjs-client\n\t```\n\n2. You can also try the [gRPC-web Go Proxy][].\n\n\t```sh\n\t$ docker-compose up -d node-server grpcwebproxy binary-client\n\t```\n\n3. Apache [APISIX](https://apisix.apache.org/) has also added gRPC-web support, and more details can be found [here](https://apisix.apache.org/blog/2022/01/25/apisix-grpc-web-integration/).\n\n4. [Nginx](https://www.nginx.com/) has a gRPC-web module ([doc](https://nginx.org/en/docs/http/ngx_http_grpc_module.html), [announcement](https://www.nginx.com/blog/nginx-1-13-10-grpc/))), and seems to work with simple configs, according to user [feedback](https://github.com/grpc/grpc-web/discussions/1322).\n\n### Server Frameworks with gRPC-Web support\n- [Armeria (JVM)](https://armeria.dev/docs/server-grpc/#grpc-web)\n- [Tonic (Rust)](https://docs.rs/tonic-web/latest/tonic_web/)\n\n### Web Frameworks Compatibility\n- **Vite** - See this [demo app](https://github.com/a2not/vite-grpc-web), as well as this [comment](https://github.com/grpc/grpc-web/issues/1242#issuecomment-1816249928).\n\n[Envoy]: https://www.envoyproxy.io\n[gRPC]: https://grpc.io\n[grpc-web-docs]: https://grpc.io/docs/languages/web\n[gRPC-web Go Proxy]: https://github.com/improbable-eng/grpc-web/tree/master/go/grpcwebproxy\n[Hello World example]: net/grpc/gateway/examples/helloworld\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\nFor information on gRPC Security Policy and reporting potentional security issues, please see [gRPC CVE Process](https://github.com/grpc/proposal/blob/master/P4-grpc-cve-process.md).\n"
  },
  {
    "path": "doc/browser-features.md",
    "content": "# gRPC-Web features for browser (HTML) clients\n\nDue to browser limitation, gRPC-Web uses a different transport\nthan the [HTTP/2 based gRPC protocol](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md).\nThe difference between the gRPC-Web\nprotocol and the HTTP/2 based gRPC protocol is specified in the core gRPC repo as [PROTOCOL-WEB](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md). \n\nIn addition to the wire-transport spec, gRPC-Web also supports features that are unique to browser (HTML) clients.\nThis document serves as the official spec for those features. As the Web platform evolves,\nwe expect some of those features will evolve too or become deprecated.\n\nOn the server-side, [Envoy](https://www.envoyproxy.io/) is the official proxy with built-in gRPC-Web support. New features will be implemented in Envoy first. For [in-process gRPC-Web support](https://github.com/grpc/grpc-web/blob/master/doc/in-process-proxy.md), we recommend that the gRPC-Web module implement only a minimum set of features, e.g. to enable local development. Those features are identified as mandatory features in this doc.\n\n# CORS support\n\n* Should follow the [CORS spec](https://developer.mozilla.org/en-US/docs/Web/HTTP/Server-Side_Access_Control) (Mandatory)\n  * Access-Control-Allow-Credentials to allow Authorization headers\n  * Access-Control-Allow-Methods to allow POST and (preflight) OPTIONS only\n  * Access-Control-Allow-Headers to whatever the preflight request carries\n  * Access-Control-Expose-Headers to allow Javascript access to `grpc-status,grpc-message` headers.\n* The client library is expected to support header overwrites to avoid preflight\n  * https://github.com/whatwg/fetch/issues/210\n* CSP support to be specified\n\n# HTTP status code mapping\n\nA grpc-web gateway is recommended to overwrite the default 200 status code and map any gateway-generated or server-generated error status to standard HTTP status codes (such as 503) when it is possible. This will help with debugging and may also improve security protection for web apps.\n\n# URL query params\n\nTo enable query-param based routing rules in reverse proxies and to avoid CORS preflight, a grpc-web client may \"advertise\" certain request data or metadata as query params. The grpc-web proxy module should remove the query params before the request is sent to the downstream gRPC server.\n\nThe actual data in query params is not interpreted by grpc-web libraries. Standard URL encoding rules shoud be followed to encode those query params.\n\n# Security\n\n* XSRF, XSS policy to be published \n\n# Compression\n\n* Full-body compression is supported and expected for all unary\nrequests/responses. The compression/decompression will be done\nby browsers, using standard Content-Encoding headers\n  * “grpc-encoding” header is not used\n  * SDCH, Brotli will be supported\n* Message-level compression for streamed requests/responses is not supported\nbecause manual compression/decompression is prohibitively expensive using JS\n"
  },
  {
    "path": "doc/in-process-proxy.md",
    "content": "# Overview\n\nIn-process proxies allow a browser client to talk to a gRPC server directly without relying on any intermediary process\nsuch as an Envoy proxy. This document provides a high-level design guidelines on how we expect such a \"proxy\" to work.\n\n# The choice of HTTP stack\n\nWe strongly recommend that the gRPC-Web module use the default HTTP stack provided by the language platform, or in the case of Java,\nthe standard Java Servlet framework. This is to ensure maximum portability and to ease integration between gRPC-Web and existing Web\nframeworks.\n\nThe actual HTTP version that the HTTP stack supports may include both HTTP/1.1 and HTTP/2. In the runtime, it's up to the user-agent and \nintermediaries to negotiate the HTTP version, which is transparent to the gRPC-Web module.\n\n# Request translation\n\nFor most languages, the gRPC-Web module will handle the gRPC-Web request, perform the translation, and then proxy the request using a gRPC client \nto the gRPC server via a local socket. The gRPC-Web support is fully transparent to the gRPC server.\n\nFor some languages, such as Swift, .NET, if the gRPC server implementation uses the same HTTP stack that the gRPC-Web module uses, then gRPC-Web may be supported \ndirectly as part of the gRPC server implementation. The added complexity to the gRPC implementation itself is still a concern.\n\n# HTTP port\n\nWe expect that gRPC-Web requests are handled on a separate port. If the HTTP stack supports both HTTP/2 and HTTP/1.1, port sharing could be supported. \nHowever, since CORS is a mandatory feature for gRPC-Web proxies, port sharing should be optional for in-process proxies.\n\n# Core features\n\nThe gRPC-Web module should implement only the [core gRPC-Web features](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md) and leave to the HTTP/Web stack provided by the language platform to handle [Web-framework-level features](https://github.com/grpc/grpc-web/blob/master/doc/browser-features.md) such as XSRF, CORS policies. Some of those features may be incompatible with what Envoy supports for gRPC-Web.\n"
  },
  {
    "path": "doc/interop-test-descriptions.md",
    "content": "gRPC-Web Interop Tests\n======================\n\nThis document describes the set of tests any gRPC-Web clients or proxies need\nto implement. The proto definition for the messages and RPCs we are using for\nthe tests can be found\n[here](https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/test.proto).\n\nThe canonical set of interop tests was defined in the main\n[grpc/grpc repo](https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md).\n\nHere in gRPC-Web, we will only implement a subset of tests that's relevant to\ngRPC-Web. For example, we will not be implementing any tests involving\nclient-streaming or bidi-streaming for now. On the other hand, there are\ngRPC-Web specific tests that we will add here.\n\n```\n gRPC-Web Client  <-->  Proxy  <--> gRPC Service\n```\n\nThe idea is that we should be able to swap out any of the 3 components above\nand all the interop tests should still pass.\n\nThis repository will provide a canonical implementation of the interop test\nsuite using the Javascript client, Envoy and a gRPC service implemented in\nNode.\n\nFor any new gRPC-Web client implementation, you need to swap out the JS\nclient and make sure all tests still pass.\n\nFor any in-process proxies implementation, you need to swap out the proxy\nand the service as a unit and make sure the standard JS client will still\npass the tests.\n\n\nList of Tests\n-------------\n\n| Test Name | grpc-web-text Mode | grpc-web Binary mode |\n| --------- |:------------------:|:--------------------:|\n| empty_unary | &#10003; | &#10003; |\n| cacheable_unary | TBD | TBD |\n| large_unary | &#10003; | &#10003; |\n| client_compressed_unary | &#10003; | &#10003; |\n| server_compressed_unary | &#10003; | &#10003; |\n| client_streaming | &#10007; | &#10007; |\n| client_compressed_streaming | &#10007; | &#10007; |\n| server_streaming | &#10003; | &#10007; |\n| server_compressed_streaming | &#10003; | &#10007; |\n| ping_pong | &#10007; | &#10007; |\n| empty_stream | &#10007; | &#10007; |\n| compute_engine_creds | TBD | TBD |\n| jwt_token_creds | TBD | TBD |\n| oauth2_auth_token | TBD | TBD |\n| per_rpc_creds | TBD | TBD |\n| google_default_credentials | TBD | TBD |\n| compute_engine_channel_credentials | TBD | TBD |\n| custom_metadata * | &#10003; | &#10003; |\n| status_code_and_message * | &#10003; | &#10003; |\n| special_status_message | &#10003; | &#10003; |\n| unimplemented_method | &#10003; | &#10003; |\n| unimplemented_service | &#10003; | &#10003; |\n| cancel_after_begin | &#10007; | &#10007; |\n| cancel_after_first_response | &#10007; | &#10007; |\n| timeout_on_sleeping_server | &#10007; | &#10007; |\n\n\\* only need to implement the UnaryCall RPC\n\ngRPC-Web specific considerations\n--------------------------------\n\n### Text vs Binary mode\n\nAs mentioned in the table above, client needs to be tested in both the text\nformat `application/grpc-web-text` and the binary mode\n`application/grpc-web+proto`. The latter we don't need to test any streaming\nmethods.\n\n### CORS and other web specific scenarios\n\nWe may add specific tests to account for web-related scenarios like CORS\nhandling, etc. Mostly these are to test the connection between the browser\nclient and the proxy.\n"
  },
  {
    "path": "doc/roadmap.md",
    "content": "# gRPC-Web Roadmap\n\nThe purpose of this document is to collect all the features that we believe are\nuseful for gRPC users.\n\n## Background\n\ngRPC-Web has been developed internally at Google as part of the front-end\nstacks for Google's Web applications and cloud services. Over time we plan to\nopen-source and publish most of the features and make them available to open-source\nusers.\n\nLike everywhere, Web platforms and technologies are constantly evolving, often\nwith many inter-dependent ecosystems. As much as we like to open-source\neverything, we also need keep the balance between creating a reusable and stable\nopen-source solution and meeting those requirements unique to Google's Web applications\n(such as search). \n\n## Roadmap Features\n\n> NOTE: Due to the status of two of gRPC-Web’s core dependencies — [Google\nClosure](https://github.com/google/closure-library/issues/1214), which has been\narchived, and [Protobuf\nJavaScript](https://github.com/protocolbuffers/protobuf-javascript?tab=readme-ov-file#project-status),\nwhich is receiving only minimal updates — the gRPC-Web project is no longer able\nto deliver new, modern solutions for the open source community. As a result, we\ndo not plan to be adding new features going forward.\n>\n> We recommend you to use [gRPC-Gateway](https://github.com/grpc-ecosystem/grpc-gateway) as an alternative.\n\n### TypeScript Codebase\nMigrate the codebase to TypeScript and update the related toolchains (incl. remove\ndependency on `closure-compiler`). Enhance overall TypeScript support.\n\n### Streaming Support\n\nEnhance Fetch/streams support (e.g. cancellation support) and improve runtime\nsupport, including service workers.\n\nSee streaming roadmap [here](streaming-roadmap.md).\n\n### Non-Binary Message Encoding\n\nThe binary protobuf encoding format is not most CPU efficient for browser\nclients. Furthermore, the generated code size increases as the total protobuf\ndefinition increases.\n\nFor Google's Web applications (e.g. gmail), we use a JSON like format which is\ncomparable to JSON in efficiency but also very compact in both the message size\nand code size.\n\n### Security\n\nWe plan to publish a comprehensive guideline doc on how to create secure Web\napplications.\n\nNative support such as XSRF, XSS prevention may also be added to the gRPC-Web\nprotocol.\n\n### Web Framework Integration\n\nThis is to provide first-class support for gRPC API and gRPC-Web in popular Web\nframeworks such as Angular. \n\nNote: Dart gRPC will use gRPC-Web as the underlying implementation on the\nDart Web platform.\n\n### Non-Closure compiler support\n\nWith the addition of CommonJS style imports, gRPC-Web client stubs can now be\ncompiled with various tools such as Browserify, Webpack, etc. Let us know\nwhat else we should try!"
  },
  {
    "path": "doc/streaming-roadmap.md",
    "content": "# Streaming Roadmap\n\nThis document describes the road-map for gRPC-Web to support different streaming features.\n* Server-streaming\n* Client-streaming and half-duplex streaming\n\n## Server-streaming\n\nWe will keep improving server-streaming in the following areas:\n* Fetch cancellation support - 2024\n* Performance improvements and whatwg Fetch/streams support, including service workers - 2024\n* Finalizing keep-alive support (via Envoy) - 2024+\n* Addressing runtime behavior gaps between Fetch and XHR - 2024+\n\n## Client-streaming and half-duplex streaming\n\nWe don’t plan to support client-streaming via Fetch/upload-streams (See [Appendix](#chrome-origin-trial-on-upload-streaming) on backgrounds on the Chrome Origin Trial). As a result, half-duplex bidi streaming won’t be supported via Fetch/streams either.\n\nClient-streaming and half-duplex bidi streaming will be addressed when Full-duplex streaming is supported via WebTransport (see below).\n\n## Full-duplex streaming\n\nNot planned.\n\n## Issues with WebSockets\n\nWe have no plan to support full-duplex streaming over WebSockets (over TCP or HTTP/2). We will not publish any experimental spec for gRPC over WebSockets either.\n\nThe main issue with WebSockets is its incompatibility with HTTP, i.e. the ubiquitous Web infrastructure. This means HTTP fallback is always needed. Recent IETF proposal to tunnel WebSockets over HTTP/2 is not widely implemented either.\n\n## Appendix\n\n### Chrome Origin Trial on `upload-streaming`\n\nWe worked on a Chrome [Origin Trial](https://developers.chrome.com/origintrials/#/view_trial/3524066708417413121) \nto finalize the fetch/upload stream API spec (whatwg). One of the pending issues that blocks the final spec is to decide whether it is safe to enable\nupload-streaming over HTTP/1.1. We believe that upload-streaming should be enabled for both HTTP/2 and HTTP/1.1. Specifically for gRPC-Web, the server can't control the client deployment. As a result, if upload-streaming is only enabled over HTTP/2, a gRPC service will have to implement a non-streaming method \nas a fallback for each client-streaming method."
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '3'\nservices:\n  prereqs:\n    build:\n      context: ./\n      dockerfile: ./net/grpc/gateway/docker/prereqs/Dockerfile\n    image: grpcweb/prereqs\n  echo-server:\n    build:\n      context: ./\n      dockerfile: ./net/grpc/gateway/docker/echo_server/Dockerfile\n    depends_on:\n      - prereqs\n    image: grpcweb/echo-server\n    ports:\n      - \"9090:9090\"\n  node-server:\n    build:\n      context: ./\n      dockerfile: ./net/grpc/gateway/docker/node_server/Dockerfile\n    depends_on:\n      - prereqs\n    image: grpcweb/node-server\n    ports:\n      - \"9090:9090\"\n  node-interop-server:\n    build:\n      context: ./\n      dockerfile: ./net/grpc/gateway/docker/node_interop_server/Dockerfile\n    image: grpcweb/node-interop-server\n    ports:\n      - \"7074:7074\"\n  envoy:\n    build:\n      context: ./\n      dockerfile: ./net/grpc/gateway/docker/envoy/Dockerfile\n    image: grpcweb/envoy\n    ports:\n      - \"8080:8080\"\n    links:\n      - node-server\n  grpcwebproxy:\n    build:\n      context: ./\n      dockerfile: ./net/grpc/gateway/docker/grpcwebproxy/Dockerfile\n    image: grpcweb/grpcwebproxy\n    ports:\n      - \"8080:8080\"\n    links:\n      - node-server\n  commonjs-client:\n    build:\n      context: ./\n      dockerfile: ./net/grpc/gateway/docker/commonjs_client/Dockerfile\n    depends_on:\n      - prereqs\n    image: grpcweb/commonjs-client\n    ports:\n      - \"8081:8081\"\n  closure-client:\n    build:\n      context: ./\n      dockerfile: ./net/grpc/gateway/docker/closure_client/Dockerfile\n    depends_on:\n      - prereqs\n    image: grpcweb/closure-client\n    ports:\n      - \"8081:8081\"\n  ts-client:\n    build:\n      context: ./\n      dockerfile: ./net/grpc/gateway/docker/ts_client/Dockerfile\n    depends_on:\n      - prereqs\n    image: grpcweb/ts-client\n    ports:\n      - \"8081:8081\"\n  binary-client:\n    build:\n      context: ./\n      dockerfile: ./net/grpc/gateway/docker/binary_client/Dockerfile\n    depends_on:\n      - prereqs\n    image: grpcweb/binary-client\n    ports:\n      - \"8081:8081\"\n  interop-client:\n    build:\n      context: ./\n      dockerfile: ./net/grpc/gateway/docker/interop_client/Dockerfile\n    depends_on:\n      - prereqs\n    image: grpcweb/interop-client\n    ports:\n      - \"8081:8081\"\n  jsunit-test:\n    build:\n      context: ./\n      dockerfile: ./packages/grpc-web/docker/jsunit-test/Dockerfile\n    image: grpcweb/jsunit-test\n"
  },
  {
    "path": "etc/localhost.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIC9jCCAd4CCQCfXxHXagE8mjANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQGEwJV\nUzELMAkGA1UECAwCQ0ExITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0\nZDAeFw0xODA4MDMyMTE2NDdaFw0yMTA1MjMyMTE2NDdaMD0xCzAJBgNVBAYTAlVT\nMQswCQYDVQQIDAJDQTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2/MlKj+OtIgJm/7DywOR\nPOypfvGHXqHTpg/ZbZgflx2vMwgoAhdun2e//AlssouStadnkevPEr+uFfxkEzH3\n80iYDtcZKXY8E6692hFrp7hKnA7gcBbb7ZQ1FwG/SfKLtLcderLcQb51P7IsQkfh\nnB8hSosV9nHhdfVtsMW7L/caqB5lUHIbRsHhSw3+hzg0r0HuKxXd5HlyRXzf9cQX\n4xc5B8Ldxo3QmXDOUHDw9quuxvUn5VWppWCGn2J+f9L/5iwgciApbiMBv/CkiVrt\niYwZY+TZY5u8lmL4FtLd2tj2vNXl5ESWcL1SRGSiaYmxX1B5rg4fSAAXmcNOzZHo\n8wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCHko8eFag++9knWV8KlRRi+IdGeatU\nTejdBVnCPFc7sJf1lkUQSb0mZMv0QEO51aXGVvU46pIjTAwtzcVgPc6ZHqcZY4r3\nxscrmECThbhsEQCHqDD55OB2a06bx+ylfbBnLh+F18W+/rI+HlRxSBGclyfVto1P\naCuYvYc0qKK90Ft1joZh1tXpho/D52B4CTa0Ax/5UqSVjTt0uPDhkCZJKnoENVgh\n6hF8ehYTC6Kf6ZtbB6+GuaLXf6F96CROLifW219qxrKmGbMyJXolOxLatufnWwwv\nHw7z1FUzulJUkSRmgPJ9hFeyTjCS1BJ18glFjleLykYOtQi8kvnpFm6C\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "etc/localhost.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEA2/MlKj+OtIgJm/7DywORPOypfvGHXqHTpg/ZbZgflx2vMwgo\nAhdun2e//AlssouStadnkevPEr+uFfxkEzH380iYDtcZKXY8E6692hFrp7hKnA7g\ncBbb7ZQ1FwG/SfKLtLcderLcQb51P7IsQkfhnB8hSosV9nHhdfVtsMW7L/caqB5l\nUHIbRsHhSw3+hzg0r0HuKxXd5HlyRXzf9cQX4xc5B8Ldxo3QmXDOUHDw9quuxvUn\n5VWppWCGn2J+f9L/5iwgciApbiMBv/CkiVrtiYwZY+TZY5u8lmL4FtLd2tj2vNXl\n5ESWcL1SRGSiaYmxX1B5rg4fSAAXmcNOzZHo8wIDAQABAoIBAFPnJL5BEIb9fezr\n+nRvH/BFt0KdkC4hPUOTuDV+Wk6jHDozWk+x8JkOUsYqMjTJ2WVCPtgDRDK6vAXX\nCbXo0dUUVC0VEJwoZjJ77iBJlO+d9ZgidKtNjQfMCZSFLhtfUrvVPoGXyT2rEb8C\nkK+YDBAqL+DnvbENMBx3SyirxQQ+YetAUSxiZagtjKlax1bhXF/JCj816ezDqOzR\nZVx4MJiJg3oD+zKlwP+IaFlANIuW2W7+LbNzPpdXER4gafRzyjRy5ksO9NFO11Bu\n2srJbAMZEr0MCEBjf5rD7CPuvhTTEcgk6CNPsIEt8zzMSZUMeS0xaIv0W1FKiw+R\nBENntsECgYEA84fSMRApKaweeBrthPKR1ucnv3EHxn1l1mz45bp+2euHB6jUul9D\n629mMv8J9PVdcPF5ck7YpCjslWm6oOhtKMemuwJm61cRF44Lz7jtLm3zNJMGhpbh\n6Q0GoIVcyMrW79BODbEIU5SlWp0Usyjo/4CZEP5adho1JNTDHCyvEVUCgYEA5zY6\ntbfu+YYgICBnaRkGgdCRBxMurxdPrgbwvrKSMerYE9fufpgvZc5wwx02rJX0psuo\nJNGLAkPJyimZCYhY/hxWwXQX8X4BhkKK2aFyBMaDIBA0h+unOwTxHrebQNprot3h\nYVT8+tfZf8bGPl+dBs3Qf+WOESjRSyO9jr5BMScCgYBfI4mPF1Qtbot8unBeRvGI\ntkeF999kwOp/CZV3EhOqiOP4rxFkOgFrwdp4Q8CdDRpTHFMov/rMrxw2BtcdM5Ap\npU3Ss06H1DzeKeUdYo5uXA/uUx3yiJF7HVagcVldLDkp+QP1P1sUY/bxXnqOv4W/\nA3tI80Vd7EEkwWXz5NUD/QKBgGXhYXFdQTI2RcWiQa7v1gwxqRYi/7krXnLioAaH\njR/tyZTE21RxHsGPe+Sd5M+brBgrOUYwBz7SPAKW3dZzfDNMrXXFAB/rVCSjAafw\nGdu81V61hVA3KJM7FDxiz0h+dltnxb4rwuWNY0uIfSZS31B2NF+G+VjaUY74irhx\nYSyVAoGANrn70s5+cJDWcmDhaFNU/J/X2Q8GgTyBRd02FIvuv7BXgd9TZ7bUVTws\n1nsQCCEVJqj4ksddVRq33NvsnjrgetGYe1LGl3uLakqaXd7iJXFCice3ZuFFrp9o\nIq2sUgG+9K8WFqNhANRKBVd32IpQzjIMAAJSbuG3EFZDLZJqxDs=\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "javascript/net/grpc/web/abstractclientbase.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n/**\n * @fileoverview gRPC browser client library.\n *\n * Base interface for gRPC Web JS clients\n *\n * @author stanleycheung@google.com (Stanley Cheung)\n */\ngoog.module('grpc.web.AbstractClientBase');\n\ngoog.module.declareLegacyNamespace();\n\n\nconst ClientReadableStream = goog.require('grpc.web.ClientReadableStream');\nconst MethodDescriptor = goog.require('grpc.web.MethodDescriptor');\nconst RpcError = goog.require('grpc.web.RpcError');\n\n\n/**\n * @constructor\n * @struct\n * @final\n */\nconst PromiseCallOptions = function() {};\n\n/**\n * An AbortSignal to abort the call.\n * @type {AbortSignal|undefined}\n */\nPromiseCallOptions.prototype.signal;\n\n\n/**\n * This interface represents a grpc-web client\n * @interface\n */\nconst AbstractClientBase = class {\n  constructor() {}\n\n  /**\n   * @abstract\n   * @template REQUEST, RESPONSE\n   * @param {string} method The method to invoke\n   * @param {REQUEST} requestMessage The request proto\n   * @param {!Object<string, string>} metadata User defined call metadata\n   * @param {!MethodDescriptor<REQUEST, RESPONSE>}\n   *   methodDescriptor Information of this RPC method\n   * @param {function(?RpcError, ?)}\n   *   callback A callback function which takes (error, RESPONSE or null)\n   * @return {!ClientReadableStream<RESPONSE>}\n   */\n  rpcCall(method, requestMessage, metadata, methodDescriptor, callback) {}\n\n  /**\n   * @abstract\n   * @protected\n   * @template REQUEST, RESPONSE\n   * @param {string} method The method to invoke\n   * @param {REQUEST} requestMessage The request proto\n   * @param {!Object<string, string>} metadata User defined call metadata\n   * @param {!MethodDescriptor<REQUEST, RESPONSE>}\n   *   methodDescriptor Information of this RPC method\n   * @param options Options for the call\n   * @return {!IThenable<RESPONSE>}\n   *   A promise that resolves to the response message\n   */\n  thenableCall(method, requestMessage, metadata, methodDescriptor, options) {}\n\n  /**\n   * @abstract\n   * @template REQUEST, RESPONSE\n   * @param {string} method The method to invoke\n   * @param {REQUEST} requestMessage The request proto\n   * @param {!Object<string, string>} metadata User defined call metadata\n   * @param {!MethodDescriptor<REQUEST, RESPONSE>}\n   *   methodDescriptor Information of this RPC method\n   * @return {!ClientReadableStream<RESPONSE>} The Client Readable Stream\n   */\n  serverStreaming(method, requestMessage, metadata, methodDescriptor) {}\n};\n\n/**\n * Get the hostname of the current request.\n * @template REQUEST, RESPONSE\n * @param {string} method\n * @param {!MethodDescriptor<REQUEST,RESPONSE>} methodDescriptor\n * @return {string}\n */\nfunction getHostname(method, methodDescriptor) {\n  // method = hostname + methodDescriptor.name(relative path of this method)\n  return method.substr(0, method.length - methodDescriptor.name.length);\n}\n\n\nexports = {AbstractClientBase, PromiseCallOptions, getHostname};\n"
  },
  {
    "path": "javascript/net/grpc/web/calloptions.js",
    "content": "/**\n * @fileoverview grpc.web.CallOptions\n */\n\ngoog.module('grpc.web.CallOptions');\ngoog.module.declareLegacyNamespace();\n\n/**\n * The collection of runtime options for a new RPC call.\n * @unrestricted\n */\nclass CallOptions {\n  /**\n   * @param {!Object<string, !Object>=} options\n   */\n  constructor(options) {\n    /**\n     * @const {!Object<string, !Object>}\n     * @private\n     */\n    this.properties_ = options || {};\n  }\n\n  /**\n   * Add a new CallOption or override an existing one.\n   *\n   * @param {string} name name of the CallOption that should be\n   *     added/overridden.\n   * @param {VALUE} value value of the CallOption\n   * @template VALUE\n   */\n  setOption(name, value) {\n    this.properties_[name] = value;\n  }\n\n  /**\n   * Get the value of one CallOption.\n   *\n   * @param {string} name name of the CallOption.\n   * @return {!Object} value of the CallOption. If name doesn't exist, will\n   *     return 'undefined'.\n   */\n  get(name) {\n    return this.properties_[name];\n  }\n\n  /**\n   * Remove a CallOption.\n   *\n   * @param {string} name name of the CallOption that shoud be removed.\n   */\n  removeOption(name) {\n    delete this.properties_[name];\n  }\n\n  /**\n   * @return {!Array<string>}\n   */\n  getKeys() {\n    return Object.keys(this.properties_);\n  }\n}\n\n\n\nexports = CallOptions;\n"
  },
  {
    "path": "javascript/net/grpc/web/clientoptions.js",
    "content": "goog.module('grpc.web.ClientOptions');\ngoog.module.declareLegacyNamespace();\n\nconst {StreamInterceptor, UnaryInterceptor} = goog.require('grpc.web.Interceptor');\n\n\n/**\n * Options that are available during the client construction.\n * @record\n */\nclass ClientOptions {\n  constructor() {\n    /**\n     * Whether to use the HttpCors library to pack http headers into a special\n     * url query param $httpHeaders= so that browsers can bypass CORS OPTIONS\n     * requests.\n     * @type {boolean|undefined}\n     */\n    this.suppressCorsPreflight;\n\n    /**\n     * Whether to turn on XMLHttpRequest's withCredentials flag.\n     * @type {boolean|undefined}\n     */\n    this.withCredentials;\n\n    /**\n     * Unary interceptors. Note that they are only available in grpcweb and\n     * grpcwebtext mode\n     * @type {!Array<!UnaryInterceptor>|undefined}\n     */\n    this.unaryInterceptors;\n\n    /**\n     * Stream interceptors. Note that they are only available in grpcweb and\n     * grpcwebtext mode\n     * @type {!Array<!StreamInterceptor>|undefined}\n     */\n    this.streamInterceptors;\n\n    /**\n     * Protocol buffer format for open source gRPC-Web. This attribute should be\n     * specified by the gRPC-Web build rule by default.\n     * @type {string|undefined}\n     */\n    this.format;\n\n    /**\n     * The Worker global scope. Once this option is specified, gRPC-Web will\n     * also use 'fetch' API as the underlying transport instead of native\n     * XmlHttpRequest.\n     * @type {!WorkerGlobalScope|undefined}\n     */\n    this.workerScope;\n\n    /**\n     * This is an experimental feature to reduce memory consumption\n     * during high throughput server-streaming calls by using\n     * 'streamBinaryChunks' mode FetchXmlHttpFactory.\n     * @type {boolean|undefined}\n     */\n    this.useFetchDownloadStreams;\n  }\n}\n\nexports = ClientOptions;\n"
  },
  {
    "path": "javascript/net/grpc/web/clientreadablestream.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n/**\n * @fileoverview gRPC web client Readable Stream\n *\n * This class is being returned after a gRPC streaming call has been\n * started. This class provides functionality for user to operates on\n * the stream, e.g. set onData callback, etc.\n *\n * This wraps the underlying goog.net.streams.NodeReadableStream\n *\n * @author stanleycheung@google.com (Stanley Cheung)\n */\ngoog.module('grpc.web.ClientReadableStream');\n\ngoog.module.declareLegacyNamespace();\n\n\n\n/**\n * A stream that the client can read from. Used for calls that are streaming\n * from the server side.\n *\n * @template RESPONSE\n * @interface\n */\nconst ClientReadableStream = function() {};\n\n\n/**\n * Register a callback to handle different stream events.\n *\n * Available event types for gRPC-Web:\n * 'data': The 'data' event is emitted when a new response message chunk is\n * received and successfully handled by gRPC-Web client.\n * 'status': the google RPC status of the response stream.\n * 'end': The 'end' event is emitted when all the data have been successfully\n * consumed from the stream.\n * 'error': typically, this may occur when an  underlying internal failure\n * happens, or a stream implementation attempts to push an invalid chunk of\n * data.\n * 'metadata': the response metadata. Response headers should be read via\n * 'metadata' callbacks.\n *\n * For server-streaming calls. the 'data' and 'status' callbacks (if exist)\n * will always precede 'metadata', 'error', or 'end' callbacks.\n *\n * @param {string} eventType The event type\n * @param {function(?)} callback The callback to handle the event with\n * an optional input object\n * @return {!ClientReadableStream} this object\n */\nClientReadableStream.prototype.on = goog.abstractMethod;\n\n\n\n/**\n * Remove a particular callback.\n *\n * @param {string} eventType The event type\n * @param {function(?)} callback The callback to remove\n * @return {!ClientReadableStream} this object\n */\nClientReadableStream.prototype.removeListener = goog.abstractMethod;\n\n\n\n/**\n * Close the stream.\n */\nClientReadableStream.prototype.cancel = goog.abstractMethod;\n\n\n\nexports = ClientReadableStream;\n"
  },
  {
    "path": "javascript/net/grpc/web/clientunarycallimpl.js",
    "content": "/**\n * @fileoverview This class handles ClientReadableStream returned by unary\n * calls.\n */\n\ngoog.module('grpc.web.ClientUnaryCallImpl');\n\ngoog.module.declareLegacyNamespace();\n\nconst ClientReadableStream = goog.require('grpc.web.ClientReadableStream');\n\n/**\n * @implements {ClientReadableStream<RESPONSE>}\n * @template RESPONSE\n */\nclass ClientUnaryCallImpl {\n  /**\n   * @param {!ClientReadableStream<RESPONSE>} stream\n   */\n  constructor(stream) {\n    this.stream = stream;\n  }\n\n  /**\n   * @override\n   */\n  on(eventType, callback) {\n    if (eventType == 'data' || eventType == 'error') {\n      // unary call responses and errors should be handled by the main\n      // (err, resp) => ... callback\n      return this;\n    }\n    return this.stream.on(eventType, callback);\n  }\n\n  /**\n   * @override\n   */\n  removeListener(eventType, callback) {\n    return this.stream.removeListener(eventType, callback);\n  }\n\n  /**\n   * @override\n   */\n  cancel() {\n    this.stream.cancel();\n  }\n}\n\nexports = ClientUnaryCallImpl;\n"
  },
  {
    "path": "javascript/net/grpc/web/generator/BUILD.bazel",
    "content": "load(\"@rules_cc//cc:defs.bzl\", \"cc_binary\")\n\ncc_binary(\n    name = \"protoc-gen-grpc-web\",\n    srcs = [\n        \"grpc_generator.cc\",\n    ],\n    visibility = [\"//visibility:public\"],\n    deps = [\n        \"@com_google_protobuf//:protoc_lib\",\n    ],\n)\n"
  },
  {
    "path": "javascript/net/grpc/web/generator/Makefile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nCXX ?= g++\nCPPFLAGS += -I/usr/local/include -pthread\nCXXFLAGS += -std=c++11\nLDFLAGS += -L/usr/local/lib -lprotoc -lprotobuf -lpthread -ldl\nPREFIX ?= /usr/local\nMIN_MACOS_VERSION := 10.7 # Supports OS X Lion\nSTATIC ?= yes\n\nUNAME_S := $(shell uname -s)\nifeq ($(UNAME_S),Darwin)\n  CXXFLAGS += -stdlib=libc++ -mmacosx-version-min=$(MIN_MACOS_VERSION)\nelse ifeq ($(UNAME_S),Linux)\n  ifeq ($(STATIC),yes)\n    LDFLAGS += -static\n  endif\nendif\n\nall: protoc-gen-grpc-web\n\nprotoc-gen-grpc-web: grpc_generator.o\n\t$(CXX) $^ $(LDFLAGS) -o $@\n\ninstall: protoc-gen-grpc-web\n\tmkdir -p $(PREFIX)/bin\n\tinstall protoc-gen-grpc-web $(PREFIX)/bin/protoc-gen-grpc-web\n\nclean:\n\trm -f *.o protoc-gen-grpc-web\n"
  },
  {
    "path": "javascript/net/grpc/web/generator/grpc_generator.cc",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#include <google/protobuf/compiler/code_generator.h>\n#include <google/protobuf/compiler/plugin.h>\n#include <google/protobuf/compiler/plugin.pb.h>\n#include <google/protobuf/descriptor.h>\n#include <google/protobuf/descriptor.pb.h>\n#include <google/protobuf/io/printer.h>\n#include <google/protobuf/io/zero_copy_stream.h>\n\n#include <algorithm>\n#include <iterator>\n#include <set>\n#include <string>\n\nusing google::protobuf::Descriptor;\nusing google::protobuf::Edition;\nusing google::protobuf::EnumDescriptor;\nusing google::protobuf::FieldDescriptor;\nusing google::protobuf::FileDescriptor;\nusing google::protobuf::MethodDescriptor;\nusing google::protobuf::ServiceDescriptor;\nusing google::protobuf::FieldOptions;\nusing google::protobuf::OneofDescriptor;\nusing google::protobuf::compiler::CodeGenerator;\nusing google::protobuf::compiler::GeneratorContext;\nusing google::protobuf::compiler::ParseGeneratorParameter;\nusing google::protobuf::compiler::PluginMain;\nusing google::protobuf::compiler::Version;\nusing google::protobuf::io::Printer;\nusing google::protobuf::io::ZeroCopyOutputStream;\n\nnamespace grpc {\nnamespace web {\nnamespace {\n\nusing std::string;\n\nenum Mode {\n  OP = 0,       // first party google3 one platform services\n  GRPCWEB = 1,  // client using the application/grpc-web wire format\n};\n\nenum ImportStyle {\n  CLOSURE = 0,     // goog.require(\"grpc.web.*\")\n  COMMONJS = 1,    // const grpcWeb = require(\"grpc-web\")\n  TYPESCRIPT = 2,  // import * as grpcWeb from 'grpc-web'\n};\n\nconst char GRPC_PROMISE[] = \"grpc.web.promise.GrpcWebPromise\";\n\nconst char* kKeyword[] = {\n    \"abstract\",   \"boolean\",      \"break\",      \"byte\",    \"case\",\n    \"catch\",      \"char\",         \"class\",      \"const\",   \"continue\",\n    \"debugger\",   \"default\",      \"delete\",     \"do\",      \"double\",\n    \"else\",       \"enum\",         \"export\",     \"extends\", \"false\",\n    \"final\",      \"finally\",      \"float\",      \"for\",     \"function\",\n    \"goto\",       \"if\",           \"implements\", \"import\",  \"in\",\n    \"instanceof\", \"int\",          \"interface\",  \"long\",    \"native\",\n    \"new\",        \"null\",         \"package\",    \"private\", \"protected\",\n    \"public\",     \"return\",       \"short\",      \"static\",  \"super\",\n    \"switch\",     \"synchronized\", \"this\",       \"throw\",   \"throws\",\n    \"transient\",  \"try\",          \"typeof\",     \"var\",     \"void\",\n    \"volatile\",   \"while\",        \"with\",\n};\n\n// Edit the version here prior to release\nstatic const std::string GRPC_WEB_VERSION = \"2.0.2\";\n\nstring GetProtocVersion(GeneratorContext* context) {\n  Version compiler_version;\n  context->GetCompilerVersion(&compiler_version);\n  return std::to_string(compiler_version.major()) + \".\" +\n         std::to_string(compiler_version.minor()) + \".\" +\n         std::to_string(compiler_version.patch()) +\n         compiler_version.suffix();\n}\n\nbool IsReserved(const string& ident) {\n  for (size_t i = 0; i < sizeof(kKeyword) / sizeof(kKeyword[0]); i++) {\n    if (ident == kKeyword[i]) {\n      return true;\n    }\n  }\n  return false;\n}\n\nstring GetModeVar(const Mode mode) {\n  switch (mode) {\n    case OP:\n      return \"OP\";\n    case GRPCWEB:\n      return \"GrpcWeb\";\n  }\n  return \"\";\n}\n\nstring GetDeserializeMethodName(std::map<string, string> vars) {\n  if (vars[\"mode\"] == GetModeVar(Mode::OP) && vars[\"binary\"] == \"false\") {\n    return \"deserialize\";\n  }\n  return \"deserializeBinary\";\n}\n\nstring GetSerializeMethodName(std::map<string, string> vars) {\n  if (vars[\"mode\"] == GetModeVar(Mode::OP) && vars[\"binary\"] == \"false\") {\n    return \"serialize\";\n  }\n  return \"serializeBinary\";\n}\n\nstd::string GetSerializeMethodReturnType(std::map<string, string> vars) {\n  if (vars[\"mode\"] == GetModeVar(Mode::OP) && vars[\"binary\"] == \"false\") {\n    return \"string\";\n  }\n  return \"!Uint8Array\";\n}\n\nstring LowercaseFirstLetter(string s) {\n  if (s.empty()) {\n    return s;\n  }\n  s[0] = ::tolower(s[0]);\n  return s;\n}\n\nstring Lowercase(string s) {\n  if (s.empty()) {\n    return s;\n  }\n\n  for (size_t i = 0; i < s.size(); i++) {\n    s[i] = ::tolower(s[i]);\n  }\n  return s;\n}\n\nstring UppercaseFirstLetter(string s) {\n  if (s.empty()) {\n    return s;\n  }\n  s[0] = ::toupper(s[0]);\n  return s;\n}\n\nstring Uppercase(string s) {\n  if (s.empty()) {\n    return s;\n  }\n\n  for (size_t i = 0; i < s.size(); i++) {\n    s[i] = ::toupper(s[i]);\n  }\n  return s;\n}\n\n// The following 5 functions were copied from\n// google/protobuf/src/google/protobuf/stubs/strutil.h\n\ninline bool HasPrefixString(const string& str, const string& prefix) {\n  return str.size() >= prefix.size() &&\n         str.compare(0, prefix.size(), prefix) == 0;\n}\n\n// Strips the given prefix from the string, as well as the remaining leading dot\n// if it exists.\ninline string StripPrefixString(const string& str, const string& prefix) {\n  if (!HasPrefixString(str, prefix)) {\n    return str;\n  }\n\n  string remaining_str = str.substr(prefix.size());\n  if (!remaining_str.empty() && remaining_str[0] == '.') {\n    remaining_str = remaining_str.substr(1);\n  }\n  return remaining_str;\n}\n\ninline bool HasSuffixString(const string& str, const string& suffix) {\n  return str.size() >= suffix.size() &&\n         str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;\n}\n\ninline string StripSuffixString(const string& str, const string& suffix) {\n  if (HasSuffixString(str, suffix)) {\n    return str.substr(0, str.size() - suffix.size());\n  } else {\n    return str;\n  }\n}\n\nvoid ReplaceCharacters(string* s, const char* remove, char replacewith) {\n  const char* str_start = s->c_str();\n  const char* str = str_start;\n  for (str = strpbrk(str, remove); str != nullptr;\n       str = strpbrk(str + 1, remove)) {\n    (*s)[str - str_start] = replacewith;\n  }\n}\n\n// The following function was copied from\n// google/protobuf/src/google/protobuf/compiler/cpp/cpp_helpers.cc\n\nstring StripProto(const string& filename) {\n  if (HasSuffixString(filename, \".protodevel\")) {\n    return StripSuffixString(filename, \".protodevel\");\n  } else {\n    return StripSuffixString(filename, \".proto\");\n  }\n}\n\n// The following 6 functions were copied from\n// google/protobuf/src/google/protobuf/compiler/js/js_generator.cc\n\nchar ToLowerASCII(char c) {\n  if (c >= 'A' && c <= 'Z') {\n    return (c - 'A') + 'a';\n  } else {\n    return c;\n  }\n}\n\nstd::vector<string> ParseLowerUnderscore(const string& input) {\n  std::vector<string> words;\n  string running = \"\";\n  for (size_t i = 0; i < input.size(); i++) {\n    if (input[i] == '_') {\n      if (!running.empty()) {\n        words.push_back(running);\n        running.clear();\n      }\n    } else {\n      running += ToLowerASCII(input[i]);\n    }\n  }\n  if (!running.empty()) {\n    words.push_back(running);\n  }\n  return words;\n}\n\nstring ToUpperCamel(const std::vector<string>& words) {\n  string result;\n  for (size_t i = 0; i < words.size(); i++) {\n    string word = words[i];\n    if (word[0] >= 'a' && word[0] <= 'z') {\n      word[0] = (word[0] - 'a') + 'A';\n    }\n    result += word;\n  }\n  return result;\n}\n\n// Returns the alias we assign to the module of the given .proto filename\n// when importing.\nstring ModuleAlias(const string& filename) {\n  // This scheme could technically cause problems if a file includes any 2 of:\n  //   foo/bar_baz.proto\n  //   foo_bar_baz.proto\n  //   foo_bar/baz.proto\n  //\n  // We'll worry about this problem if/when we actually see it.  This name isn't\n  // exposed to users so we can change it later if we need to.\n  string basename = StripProto(filename);\n  ReplaceCharacters(&basename, \"-\", '$');\n  ReplaceCharacters(&basename, \"/\", '_');\n  ReplaceCharacters(&basename, \".\", '_');\n  return basename + \"_pb\";\n}\n\nstring JSMessageType(const Descriptor* desc, const FileDescriptor* file) {\n  string class_name = StripPrefixString(desc->full_name(), desc->file()->package());\n  if (desc->file() == file) {\n    // [for protobuf .d.ts files only] Do not add the module prefix for local\n    // messages.\n    return class_name;\n  }\n  return ModuleAlias(desc->file()->name()) + \".\" + class_name;\n}\n\nstring JSMessageType(const Descriptor* desc) {\n  return JSMessageType(desc, nullptr);\n}\n\nstring JSElementType(const FieldDescriptor* desc, const FileDescriptor* file) {\n  switch (desc->type()) {\n    case FieldDescriptor::TYPE_DOUBLE:\n    case FieldDescriptor::TYPE_FLOAT:\n    case FieldDescriptor::TYPE_INT32:\n    case FieldDescriptor::TYPE_UINT32:\n    case FieldDescriptor::TYPE_SINT32:\n    case FieldDescriptor::TYPE_FIXED32:\n    case FieldDescriptor::TYPE_SFIXED32:\n      return \"number\";\n\n    case FieldDescriptor::TYPE_INT64:\n    case FieldDescriptor::TYPE_UINT64:\n    case FieldDescriptor::TYPE_SINT64:\n    case FieldDescriptor::TYPE_FIXED64:\n    case FieldDescriptor::TYPE_SFIXED64:\n      if (desc->options().jstype() == FieldOptions::JS_STRING) {\n        return \"string\";\n      } else {\n        return \"number\";\n      }\n\n    case FieldDescriptor::TYPE_BOOL:\n      return \"boolean\";\n\n    case FieldDescriptor::TYPE_STRING:\n      return \"string\";\n\n    case FieldDescriptor::TYPE_BYTES:\n      return \"Uint8Array | string\";\n\n    case FieldDescriptor::TYPE_ENUM:\n      if (desc->enum_type()->file() == file) {\n        // [for protobuf .d.ts files only] Do not add the module prefix for\n        // local messages.\n        return StripPrefixString(desc->enum_type()->full_name(),\n                                 desc->enum_type()->file()->package());\n      }\n      return ModuleAlias(desc->enum_type()->file()->name()) + \".\" +\n             StripPrefixString(desc->enum_type()->full_name(),\n                               desc->enum_type()->file()->package());\n\n    case FieldDescriptor::TYPE_MESSAGE:\n      return JSMessageType(desc->message_type(), file);\n\n    default:\n      return \"{}\";\n  }\n}\n\nstring JSFieldType(const FieldDescriptor* desc, const FileDescriptor* file) {\n  string js_field_type = JSElementType(desc, file);\n  if (desc->is_map()) {\n    string key_type = JSFieldType(desc->message_type()->field(0), file);\n    string value_type = JSFieldType(desc->message_type()->field(1), file);\n    return \"jspb.Map<\" + key_type + \", \" + value_type + \">\";\n  }\n  if (desc->is_repeated()) {\n    return \"Array<\" + js_field_type + \">\";\n  }\n  return js_field_type;\n}\n\nstring AsObjectFieldType(const FieldDescriptor* desc,\n                         const FileDescriptor* file) {\n  if (desc->type() != FieldDescriptor::TYPE_MESSAGE) {\n    return JSFieldType(desc, file);\n  }\n  if (desc->is_map()) {\n    const Descriptor* message = desc->message_type();\n    string key_type = AsObjectFieldType(message->field(0), file);\n    string value_type = AsObjectFieldType(message->field(1), file);\n    return \"Array<[\" + key_type + \", \" + value_type + \"]>\";\n  }\n  string field_type = JSMessageType(desc->message_type(), file) + \".AsObject\";\n  if (desc->is_repeated()) {\n    return \"Array<\" + field_type + \">\";\n  }\n  return field_type;\n}\n\nstring JSElementName(const FieldDescriptor* desc) {\n  return ToUpperCamel(ParseLowerUnderscore(desc->name()));\n}\n\nstring JSFieldName(const FieldDescriptor* desc) {\n  string js_field_name = JSElementName(desc);\n  if (desc->is_map()) {\n    js_field_name += \"Map\";\n  } else if (desc->is_repeated()) {\n    js_field_name += \"List\";\n  }\n  return js_field_name;\n}\n\n// Like ToUpperCamel except the first letter is not converted.\nstring ToCamelCase(const std::vector<string>& words) {\n  if (words.empty()) {\n    return \"\";\n  }\n  string result = words[0];\n  return result + ToUpperCamel(std::vector<string>(\n                      words.begin() + 1, words.begin() + words.size()));\n}\n\n// Like JSFieldName, but with first letter not uppercased\nstring CamelCaseJSFieldName(const FieldDescriptor* desc) {\n  string js_field_name = ToCamelCase(ParseLowerUnderscore(desc->name()));\n  if (desc->is_map()) {\n    js_field_name += \"Map\";\n  } else if (desc->is_repeated()) {\n    js_field_name += \"List\";\n  }\n  return js_field_name;\n}\n\n// Returns the name of the message with a leading dot and taking into account\n// nesting, for example \".OuterMessage.InnerMessage\", or returns empty if\n// descriptor is null. This function does not handle namespacing, only message\n// nesting.\nstring GetNestedMessageName(const Descriptor* descriptor) {\n  if (descriptor == nullptr) {\n    return \"\";\n  }\n  string result =\n      StripPrefixString(descriptor->full_name(), descriptor->file()->package());\n  // Add a leading dot if one is not already present.\n  if (!result.empty() && result[0] != '.') {\n    result = \".\" + result;\n  }\n  return result;\n}\n\n// Given a filename like foo/bar/baz.proto, returns the root directory\n// path ../../\nstring GetRootPath(const string& from_filename, const string& to_filename) {\n  if (HasPrefixString(to_filename, \"google/protobuf\")) {\n    // Well-known types (.proto files in the google/protobuf directory) are\n    // assumed to come from the 'google-protobuf' npm package.  We may want to\n    // generalize this exception later by letting others put generated code in\n    // their own npm packages.\n    return \"google-protobuf/\";\n  }\n\n  size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/');\n  if (slashes == 0) {\n    return \"./\";\n  }\n  string result = \"\";\n  for (size_t i = 0; i < slashes; i++) {\n    result += \"../\";\n  }\n  return result;\n}\n\n// Splits path immediately following the final slash, separating it into a\n// directory and file name component. Directory will contain the last\n// slash, if it's not empty.\n// If there is no slash in path, Split returns an empty directory and\n// basename set to path.\n// Output values have the property that path = directory + basename.\nvoid PathSplit(const string& path, string* directory, string* basename) {\n  string::size_type last_slash = path.rfind('/');\n  if (last_slash == string::npos) {\n    if (directory) {\n      *directory = \"\";\n    }\n    if (basename) {\n      *basename = path;\n    }\n  } else {\n    if (directory) {\n      *directory = path.substr(0, last_slash + 1);\n    }\n    if (basename) {\n      *basename = path.substr(last_slash + 1);\n    }\n  }\n}\n\n// Returns the basename of a file.\nstring GetBasename(string filename) {\n  string basename;\n  PathSplit(filename, nullptr, &basename);\n  return basename;\n}\n\n//Adds $ suffix to reserved method names to avoid conflicts.\nstatic bool IsReservedMethodName(const std::string& name) {\n  static const std::unordered_set<std::string> reserved = {\n    \"extension\",\n    \"jspbmessageid\"\n  };\n\n  std::string lower_name = Lowercase(name);\n\n  return reserved.count(lower_name) > 0;\n}\n\nstatic std::string SafeAccessorName(const std::string& name) {\n  std::string result = name;\n  if (IsReservedMethodName(name)) {\n    result += \"$\";\n  }\n  return result;\n}\n\n// Finds all message types used in all services in the file. Return results as a\n// map of full names to descriptors to get sorted results and deterministic\n// build outputs.\nstd::map<string, const Descriptor*> GetAllMessages(const FileDescriptor* file) {\n  std::map<string, const Descriptor*> messages;\n  for (int s = 0; s < file->service_count(); ++s) {\n    const ServiceDescriptor* service = file->service(s);\n    for (int m = 0; m < service->method_count(); ++m) {\n      const MethodDescriptor* method = service->method(m);\n      messages[method->input_type()->full_name()] = method->input_type();\n      messages[method->output_type()->full_name()] = method->output_type();\n    }\n  }\n\n  return messages;\n}\n\nvoid PrintClosureDependencies(Printer* printer, const FileDescriptor* file) {\n  for (const auto& entry : GetAllMessages(file)) {\n    printer->Print(\"goog.require('proto.$full_name$');\\n\", \"full_name\",\n                   entry.second->full_name());\n  }\n}\n\nvoid PrintCommonJsMessagesDeps(Printer* printer, const FileDescriptor* file) {\n  std::map<string, string> vars;\n\n  for (int i = 0; i < file->dependency_count(); i++) {\n    const string& name = file->dependency(i)->name();\n    vars[\"alias\"] = ModuleAlias(name);\n    vars[\"dep_filename\"] = GetRootPath(file->name(), name) + StripProto(name);\n    // we need to give each cross-file import an alias\n    printer->Print(vars, \"\\nvar $alias$ = require('$dep_filename$_pb.js')\\n\");\n  }\n\n  const string& package = file->package();\n  vars[\"package_name\"] = package;\n\n  if (!package.empty()) {\n    size_t offset = 0;\n    size_t dotIndex = package.find('.');\n\n    printer->Print(vars, \"const proto = {};\\n\");\n\n    while (dotIndex != string::npos) {\n      vars[\"current_package_ns\"] = package.substr(0, dotIndex);\n      printer->Print(vars, \"proto.$current_package_ns$ = {};\\n\");\n\n      offset = dotIndex + 1;\n      dotIndex = package.find('.', offset);\n    }\n  }\n\n  // need to import the messages from our own file\n  vars[\"filename\"] = GetBasename(StripProto(file->name()));\n\n  if (!package.empty()) {\n    printer->Print(vars,\n                   \"proto.$package_name$ = require('./$filename$_pb.js');\\n\\n\");\n  } else {\n    printer->Print(vars, \"const proto = require('./$filename$_pb.js');\\n\\n\");\n  }\n}\n\nvoid PrintES6Imports(Printer* printer, const FileDescriptor* file) {\n  std::map<string, string> vars;\n\n  printer->Print(\"import * as grpcWeb from 'grpc-web';\\n\\n\");\n\n  std::set<string> imports;\n  for (const auto& entry : GetAllMessages(file)) {\n    const string& proto_filename = entry.second->file()->name();\n    string dep_filename = GetRootPath(file->name(), proto_filename) + StripProto(proto_filename);\n    if (imports.find(dep_filename) != imports.end()) {\n      continue;\n    }\n    imports.insert(dep_filename);\n    // We need to give each cross-file import an alias.\n    printer->Print(\"import * as $alias$ from '$dep_filename$_pb'; // proto import: \\\"$proto_filename$\\\"\\n\",\n                   \"alias\", ModuleAlias(proto_filename),\n                   \"dep_filename\", dep_filename,\n                   \"proto_filename\", proto_filename);\n  }\n  printer->Print(\"\\n\\n\");\n}\n\nvoid PrintTypescriptFile(Printer* printer, const FileDescriptor* file,\n                         std::map<string, string> vars) {\n  PrintES6Imports(printer, file);\n  for (int service_index = 0; service_index < file->service_count();\n       ++service_index) {\n    printer->Print(\"export class \");\n    const ServiceDescriptor* service = file->service(service_index);\n    vars[\"service_name\"] = service->name();\n    printer->Print(vars, \"$service_name$Client {\\n\");\n    printer->Indent();\n    printer->Print(\n        \"client_: grpcWeb.AbstractClientBase;\\n\"\n        \"hostname_: string;\\n\"\n        \"credentials_: null | { [index: string]: string; };\\n\"\n        \"options_: null | { [index: string]: any; };\\n\\n\"\n        \"constructor (hostname: string,\\n\"\n        \"             credentials?: null | { [index: string]: string; },\\n\"\n        \"             options?: null | { [index: string]: any; }) {\\n\");\n    printer->Indent();\n    printer->Print(\"if (!options) options = {};\\n\");\n    printer->Print(\"if (!credentials) credentials = {};\\n\");\n    if (vars[\"mode\"] == GetModeVar(Mode::GRPCWEB)) {\n      printer->Print(vars, \"options['format'] = '$format$';\\n\\n\");\n    }\n    printer->Print(vars,\n                   \"this.client_ = new grpcWeb.$mode$ClientBase(options);\\n\"\n                   \"this.hostname_ = hostname.replace(/\\\\/+$$/, '');\\n\"\n                   \"this.credentials_ = credentials;\\n\"\n                   \"this.options_ = options;\\n\");\n    printer->Outdent();\n    printer->Print(\"}\\n\\n\");\n\n    for (int method_index = 0; method_index < service->method_count();\n         ++method_index) {\n      const MethodDescriptor* method = service->method(method_index);\n      vars[\"js_method_name\"] = LowercaseFirstLetter(method->name());\n      vars[\"method_name\"] = method->name();\n      vars[\"input_type\"] = JSMessageType(method->input_type());\n      vars[\"output_type\"] = JSMessageType(method->output_type());\n      vars[\"serialize_func_name\"] = GetSerializeMethodName(vars);\n      vars[\"deserialize_func_name\"] = GetDeserializeMethodName(vars);\n      vars[\"method_type\"] = method->server_streaming()\n                                ? \"grpcWeb.MethodType.SERVER_STREAMING\"\n                                : \"grpcWeb.MethodType.UNARY\";\n      if (!method->client_streaming()) {\n        printer->Print(vars,\n                       \"methodDescriptor$method_name$ = \"\n                       \"new grpcWeb.MethodDescriptor(\\n\");\n        printer->Indent();\n        printer->Print(vars,\n                       \"'/$package_dot$$service_name$/$method_name$',\\n\"\n                       \"$method_type$,\\n\"\n                       \"$input_type$,\\n\"\n                       \"$output_type$,\\n\"\n                       \"(request: $input_type$) => {\\n\"\n                       \"  return request.$serialize_func_name$();\\n\"\n                       \"},\\n\"\n                       \"$output_type$.$deserialize_func_name$\\n\");\n        printer->Outdent();\n        printer->Print(\");\\n\\n\");\n        if (method->server_streaming()) {\n          printer->Print(vars, \"$js_method_name$(\\n\");\n          printer->Indent();\n          printer->Print(vars,\n                         \"request: $input_type$,\\n\"\n                         \"metadata?: grpcWeb.Metadata): \"\n                         \"grpcWeb.ClientReadableStream<$output_type$> {\\n\");\n          printer->Print(vars, \"return this.client_.serverStreaming(\\n\");\n          printer->Indent();\n          printer->Print(vars,\n                         \"this.hostname_ +\\n\"\n                         \"  '/$package_dot$$service_name$/$method_name$',\\n\"\n                         \"request,\\n\"\n                         \"metadata || {},\\n\"\n                         \"this.methodDescriptor$method_name$);\\n\");\n          printer->Outdent();\n          printer->Outdent();\n          printer->Print(\"}\\n\\n\");\n        } else {\n          printer->Print(vars, \"$js_method_name$(\\n\");\n          printer->Indent();\n          printer->Print(vars,\n                         \"request: $input_type$,\\n\"\n                         \"metadata?: grpcWeb.Metadata | null): \"\n                         \"$promise$<$output_type$>;\\n\\n\");\n          printer->Outdent();\n\n          printer->Print(vars, \"$js_method_name$(\\n\");\n          printer->Indent();\n          printer->Print(vars,\n                         \"request: $input_type$,\\n\"\n                         \"metadata: grpcWeb.Metadata | null,\\n\"\n                         \"callback: (err: grpcWeb.RpcError,\\n\"\n                         \"           response: $output_type$) => void): \"\n                         \"grpcWeb.ClientReadableStream<$output_type$>;\\n\\n\");\n          printer->Outdent();\n\n          printer->Print(vars, \"$js_method_name$(\\n\");\n          printer->Indent();\n          printer->Print(vars,\n                         \"request: $input_type$,\\n\"\n                         \"metadata?: grpcWeb.Metadata | null,\\n\"\n                         \"callback?: (err: grpcWeb.RpcError,\\n\"\n                         \"           response: $output_type$) => void) {\\n\");\n          printer->Print(vars, \"if (callback !== undefined) {\\n\");\n          printer->Indent();\n          printer->Print(vars, \"return this.client_.rpcCall(\\n\");\n          printer->Indent();\n          printer->Print(vars,\n                         \"this.hostname_ +\\n\"\n                         \"  '/$package_dot$$service_name$/$method_name$',\\n\"\n                         \"request,\\n\"\n                         \"metadata || {},\\n\"\n                         \"this.methodDescriptor$method_name$,\\n\"\n                         \"callback);\\n\");\n          printer->Outdent();\n          printer->Outdent();\n          printer->Print(vars,\n                         \"}\\n\"\n                         \"return this.client_.unaryCall(\\n\");\n          printer->Print(vars,\n                         \"this.hostname_ +\\n\"\n                         \"  '/$package_dot$$service_name$/$method_name$',\\n\"\n                         \"request,\\n\"\n                         \"metadata || {},\\n\"\n                         \"this.methodDescriptor$method_name$);\\n\");\n          printer->Outdent();\n          printer->Print(\"}\\n\\n\");\n        }\n      }\n    }\n    printer->Outdent();\n    printer->Print(\"}\\n\\n\");\n  }\n}\n\nvoid PrintGrpcWebDtsClientClass(Printer* printer, const FileDescriptor* file,\n                                const string& client_type) {\n  std::map<string, string> vars;\n  vars[\"client_type\"] = client_type;\n  vars[\"promise\"] = \"Promise\";\n  for (int service_index = 0; service_index < file->service_count();\n       ++service_index) {\n    printer->Print(\"export class \");\n    const ServiceDescriptor* service = file->service(service_index);\n    vars[\"service_name\"] = service->name();\n    printer->Print(vars, \"$service_name$$client_type$ {\\n\");\n    printer->Indent();\n    printer->Print(\n        \"constructor (hostname: string,\\n\"\n        \"             credentials?: null | { [index: string]: string; },\\n\"\n        \"             options?: null | { [index: string]: any; });\\n\\n\");\n    for (int method_index = 0; method_index < service->method_count();\n         ++method_index) {\n      const MethodDescriptor* method = service->method(method_index);\n      vars[\"js_method_name\"] = LowercaseFirstLetter(method->name());\n      vars[\"input_type\"] = JSMessageType(method->input_type());\n      vars[\"output_type\"] = JSMessageType(method->output_type());\n      if (!method->client_streaming()) {\n        if (method->server_streaming()) {\n          printer->Print(vars, \"$js_method_name$(\\n\");\n          printer->Indent();\n          printer->Print(vars,\n                         \"request: $input_type$,\\n\"\n                         \"metadata?: grpcWeb.Metadata\\n\");\n          printer->Outdent();\n          printer->Print(vars,\n                         \"): grpcWeb.ClientReadableStream<$output_type$>;\\n\\n\");\n        } else {\n          if (vars[\"client_type\"] == \"PromiseClient\") {\n            printer->Print(vars, \"$js_method_name$(\\n\");\n            printer->Indent();\n            printer->Print(vars,\n                           \"request: $input_type$,\\n\"\n                           \"metadata?: grpcWeb.Metadata\\n\");\n            printer->Outdent();\n            printer->Print(vars, \"): $promise$<$output_type$>;\\n\\n\");\n          } else {\n            printer->Print(vars, \"$js_method_name$(\\n\");\n            printer->Indent();\n            printer->Print(vars,\n                           \"request: $input_type$,\\n\"\n                           \"metadata: grpcWeb.Metadata | undefined,\\n\"\n                           \"callback: (err: grpcWeb.RpcError,\\n\"\n                           \"           response: $output_type$) => void\\n\");\n            printer->Outdent();\n            printer->Print(vars,\n                           \"): grpcWeb.ClientReadableStream<$output_type$>;\");\n            printer->Print(\"\\n\\n\");\n          }\n        }\n      }\n    }\n    printer->Outdent();\n    printer->Print(\"}\\n\\n\");\n  }\n}\n\nvoid PrintGrpcWebDtsFile(Printer* printer, const FileDescriptor* file) {\n  PrintES6Imports(printer, file);\n  PrintGrpcWebDtsClientClass(printer, file, \"Client\");\n  PrintGrpcWebDtsClientClass(printer, file, \"PromiseClient\");\n}\n\nvoid PrintProtoDtsEnum(Printer* printer, const EnumDescriptor* desc) {\n  std::map<string, string> vars;\n  vars[\"enum_name\"] = desc->name();\n\n  // Use regular enums for broad TypeScript compatibility. `const enum`\n  // triggers TS2748 when `verbatimModuleSyntax` is enabled (default in\n  // TypeScript 5.9+), so prefer `enum` here.\n  printer->Print(vars, \"export enum $enum_name$ {\\n\");\n  printer->Indent();\n  for (int i = 0; i < desc->value_count(); i++) {\n    vars[\"value_name\"] = Uppercase(desc->value(i)->name());\n    vars[\"value_number\"] = std::to_string(desc->value(i)->number());\n    printer->Print(vars, \"$value_name$ = $value_number$,\\n\");\n  }\n  printer->Outdent();\n  printer->Print(\"}\\n\");\n}\n\nvoid PrintProtoDtsOneofCase(Printer* printer, const OneofDescriptor* desc) {\n  std::map<string, string> vars;\n  vars[\"oneof_name\"] = ToUpperCamel(ParseLowerUnderscore(desc->name()));\n  vars[\"oneof_name_upper\"] = Uppercase(desc->name());\n\n  // Oneof case enums also use regular enums to avoid ambient `const enum`\n  // issues under `verbatimModuleSyntax`.\n  printer->Print(vars, \"export enum $oneof_name$Case {\\n\");\n  printer->Indent();\n  printer->Print(vars, \"$oneof_name_upper$_NOT_SET = 0,\\n\");\n  for (int i = 0; i < desc->field_count(); i++) {\n    const FieldDescriptor* field = desc->field(i);\n    vars[\"field_name\"] = Uppercase(field->name());\n    vars[\"field_number\"] = std::to_string(field->number());\n    printer->Print(vars, \"$field_name$ = $field_number$,\\n\");\n  }\n  printer->Outdent();\n  printer->Print(\"}\\n\");\n}\n\nvoid PrintProtoDtsMessage(Printer* printer, const Descriptor* desc,\n                          const FileDescriptor* file) {\n  const string& class_name = desc->name();\n  std::map<string, string> vars;\n  vars[\"class_name\"] = class_name;\n\n  printer->Print(vars, \"export class $class_name$ extends jspb.Message {\\n\");\n  printer->Indent();\n\n  printer->Print(vars, \"constructor();\\n\" \"constructor(opt_data?: $class_name$.AsObject);\\n\");\n\n  for (int i = 0; i < desc->field_count(); i++) {\n    const FieldDescriptor* field = desc->field(i);\n\n    vars[\"js_field_name\"] = SafeAccessorName(JSFieldName(field));\n    vars[\"js_field_type\"] = JSFieldType(field, file);\n    if (field->type() != FieldDescriptor::TYPE_MESSAGE ||\n        field->is_repeated()) {\n      printer->Print(vars, \"get$js_field_name$(): $js_field_type$;\\n\");\n    } else {\n      printer->Print(vars,\n                     \"get$js_field_name$(): $js_field_type$ | undefined;\\n\");\n    }\n    if (field->type() == FieldDescriptor::TYPE_BYTES && !field->is_repeated()) {\n      printer->Print(vars,\n                     \"get$js_field_name$_asU8(): Uint8Array;\\n\"\n                     \"get$js_field_name$_asB64(): string;\\n\");\n    }\n    if (!field->is_map() && (field->type() != FieldDescriptor::TYPE_MESSAGE ||\n                             field->is_repeated())) {\n      printer->Print(vars,\n                     \"set$js_field_name$(value: $js_field_type$): \"\n                     \"$class_name$;\\n\");\n    } else if (!field->is_map()) {\n      printer->Print(vars,\n                     \"set$js_field_name$(value?: $js_field_type$): \"\n                     \"$class_name$;\\n\");\n    }\n    if (field->has_presence()) {\n      printer->Print(vars, \"has$js_field_name$(): boolean;\\n\");\n    }\n    if (field->type() == FieldDescriptor::TYPE_MESSAGE ||\n        field->has_presence() || field->is_repeated() || field->is_map()) {\n      printer->Print(vars, \"clear$js_field_name$(): $class_name$;\\n\");\n    }\n    if (field->is_repeated() && !field->is_map()) {\n\n      vars[\"js_field_name\"] = SafeAccessorName(JSElementName(field));\n      vars[\"js_field_type\"] = JSElementType(field, file);\n      if (field->type() != FieldDescriptor::TYPE_MESSAGE) {\n        printer->Print(vars,\n                       \"add$js_field_name$(value: $js_field_type$, \"\n                       \"index?: number): $class_name$;\\n\");\n      } else {\n        printer->Print(vars,\n                       \"add$js_field_name$(value?: $js_field_type$, \"\n                       \"index?: number): $js_field_type$;\\n\");\n      }\n    }\n\n    printer->Print(\"\\n\");\n  }\n\n  for (int i = 0; i < desc->real_oneof_decl_count(); i++) {\n    const OneofDescriptor *oneof = desc->real_oneof_decl(i);\n    vars[\"js_oneof_name\"] = ToUpperCamel(ParseLowerUnderscore(oneof->name()));\n    printer->Print(\n        vars, \"get$js_oneof_name$Case(): $class_name$.$js_oneof_name$Case;\\n\");\n    printer->Print(\"\\n\");\n  }\n\n  printer->Print(\n      vars,\n      \"serializeBinary(): Uint8Array;\\n\"\n      \"toObject(includeInstance?: boolean): \"\n      \"$class_name$.AsObject;\\n\"\n      \"static toObject(includeInstance: boolean, msg: $class_name$): \"\n      \"$class_name$.AsObject;\\n\"\n      \"static serializeBinaryToWriter(message: $class_name$, writer: \"\n      \"jspb.BinaryWriter): void;\\n\"\n      \"static deserializeBinary(bytes: Uint8Array): $class_name$;\\n\"\n      \"static deserializeBinaryFromReader(message: $class_name$, reader: \"\n      \"jspb.BinaryReader): $class_name$;\\n\");\n  printer->Outdent();\n  printer->Print(\"}\\n\\n\");\n\n  printer->Print(vars, \"export namespace $class_name$ {\\n\");\n  printer->Indent();\n  printer->Print(\"export type AsObject = {\\n\");\n  printer->Indent();\n  for (int i = 0; i < desc->field_count(); i++) {\n    const FieldDescriptor* field = desc->field(i);\n    \n    string js_field_name = CamelCaseJSFieldName(field);\n    if (IsReserved(js_field_name)) {\n      js_field_name = \"pb_\" + js_field_name;\n    }\n\n    vars[\"js_field_name\"] = js_field_name;\n    vars[\"js_field_type\"] = AsObjectFieldType(field, file);\n    if (!field->has_presence()) {\n      printer->Print(vars, \"$js_field_name$: $js_field_type$;\\n\");\n    } else {\n      printer->Print(vars, \"$js_field_name$?: $js_field_type$;\\n\");\n    }\n  }\n  printer->Outdent();\n  printer->Print(\"};\\n\");\n\n  for (int i = 0; i < desc->nested_type_count(); i++) {\n    if (desc->nested_type(i)->options().map_entry()) {\n      continue;\n    }\n    printer->Print(\"\\n\");\n    PrintProtoDtsMessage(printer, desc->nested_type(i), file);\n  }\n\n  for (int i = 0; i < desc->enum_type_count(); i++) {\n    printer->Print(\"\\n\");\n    PrintProtoDtsEnum(printer, desc->enum_type(i));\n  }\n\n  for (int i = 0; i < desc->oneof_decl_count(); i++) {\n    printer->Print(\"\\n\");\n    PrintProtoDtsOneofCase(printer, desc->oneof_decl(i));\n  }\n\n  printer->Outdent();\n  printer->Print(\"}\\n\\n\");\n}\n\nvoid PrintProtoDtsFile(Printer* printer, const FileDescriptor* file) {\n  printer->Print(\"import * as jspb from 'google-protobuf'\\n\\n\");\n\n  for (int i = 0; i < file->dependency_count(); i++) {\n    const string& proto_filename = file->dependency(i)->name();\n    // We need to give each cross-file import an alias.\n    printer->Print(\"import * as $alias$ from '$dep_filename$_pb'; // proto import: \\\"$proto_filename$\\\"\\n\",\n                   \"alias\", ModuleAlias(proto_filename),\n                   \"dep_filename\", GetRootPath(file->name(), proto_filename) + StripProto(proto_filename),\n                   \"proto_filename\", proto_filename);\n  }\n  printer->Print(\"\\n\\n\");\n\n  for (int i = 0; i < file->message_type_count(); i++) {\n    PrintProtoDtsMessage(printer, file->message_type(i), file);\n  }\n\n  for (int i = 0; i < file->enum_type_count(); i++) {\n    PrintProtoDtsEnum(printer, file->enum_type(i));\n  }\n}\n\nvoid PrintFileHeader(Printer* printer, const std::map<string, string>& vars) {\n  printer->Print(\n      vars,\n      \"/**\\n\"\n      \" * @fileoverview gRPC-Web generated client stub for $package$\\n\"\n      \" * @enhanceable\\n\"\n      \" * @public\\n\"\n      \" */\\n\\n\"\n      \"// Code generated by protoc-gen-grpc-web. DO NOT EDIT.\\n\"\n      \"// versions:\\n\"\n      \"// \\tprotoc-gen-grpc-web v$version$\\n\"\n      \"// \\tprotoc              v$protoc_version$\\n\"\n      \"// source: $source_file$\\n\\n\\n\"\n      \"/* eslint-disable */\\n\"\n      \"// @ts-nocheck\\n\\n\\n\");\n}\n\nvoid PrintMethodDescriptorFile(Printer* printer,\n                               std::map<string, string> vars) {\n  printer->Print(\n      vars,\n      \"/**\\n\"\n      \" * @fileoverview gRPC-Web generated MethodDescriptors for $package$\\n\");\n  if (vars[\"plugins\"].empty()) {\n    printer->Print(\" * @enhanceable\\n\");\n  }\n  printer->Print(\n      \" * @public\\n\"\n      \" */\\n\\n\"\n      \"// Code generated by protoc-gen-grpc-web. DO NOT EDIT.\\n\"\n      \"// versions:\\n\"\n      \"// \\tprotoc-gen-grpc-web v$version$\\n\"\n      \"// \\tprotoc              v$protoc_version$\\n\"\n      \"// source: $source_file$\\n\\n\\n\"\n      \"/* eslint-disable */\\n\"\n      \"// @ts-nocheck\\n\\n\\n\");\n\n  printer->Print(vars,\n                 \"goog.provide('proto.$package_dot$$class_name$.$\"\n                 \"method_name$MethodDescriptor');\\n\\n\");\n  if (!vars[\"plugins\"].empty()) {\n    printer->Print(vars,\n                   \"goog.require('$plugins$.$package_dot$$class_name$.$\"\n                   \"method_name$MethodDescriptor');\\n\");\n  }\n  printer->Print(vars, \"goog.require('grpc.web.MethodDescriptor');\\n\");\n  printer->Print(vars, \"goog.require('grpc.web.MethodType');\\n\");\n  printer->Print(vars, \"goog.require('$in_type$');\\n\");\n  if (vars[\"out_type\"] != vars[\"in_type\"]) {\n    printer->Print(vars, \"goog.require('$out_type$');\\n\");\n  }\n  printer->Print(vars, \"\\n\\ngoog.scope(function() {\\n\\n\");\n\n  printer->Print(\n      vars,\n      \"/**\\n\"\n      \" * @const\\n\"\n      \" * @type {!grpc.web.MethodDescriptor<\\n\"\n      \" *   !proto.$in$,\\n\"\n      \" *   !proto.$out$>}\\n\"\n      \" */\\n\"\n      \"proto.$package_dot$$class_name$.$method_name$MethodDescriptor = \\n\");\n  printer->Indent();\n  printer->Indent();\n  printer->Print(vars, \"new grpc.web.MethodDescriptor(\\n\");\n  printer->Indent();\n  printer->Indent();\n  printer->Print(vars,\n                 \"'/$package_dot$$service_name$/$method_name$',\\n\"\n                 \"$method_type$,\\n\"\n                 \"$in_type$,\\n\");\n  printer->Print(vars,\n                 \"$out_type$,\\n\"\n                 \"/**\\n\"\n                 \" * @param {!proto.$in$} request\\n\");\n  printer->Print(\n      (\" * @return {\" + GetSerializeMethodReturnType(vars) + \"}\\n\").c_str());\n  printer->Print(\n      \" */\\n\"\n      \"function(request) {\\n\");\n  printer->Print(\n      (\"  return request.\" + GetSerializeMethodName(vars) + \"();\\n\").c_str());\n  printer->Print(\"},\\n\");\n  printer->Print(vars,\n                 (\"$out_type$.\" + GetDeserializeMethodName(vars)).c_str());\n  printer->Print(vars, \");\\n\\n\\n\");\n  printer->Outdent();\n  printer->Outdent();\n  printer->Outdent();\n  printer->Outdent();\n  printer->Print(\"}); // goog.scope\\n\\n\");\n}\n\nvoid PrintServiceConstructor(Printer* printer, std::map<string, string> vars,\n                             bool is_promise) {\n  vars[\"is_promise\"] = is_promise ? \"Promise\" : \"\";\n  printer->Print(vars,\n                 \"/**\\n\"\n                 \" * @param {string} hostname\\n\"\n                 \" * @param {?Object} credentials\\n\"\n                 \" * @param {?grpc.web.ClientOptions} options\\n\"\n                 \" * @constructor\\n\"\n                 \" * @struct\\n\"\n                 \" * @final\\n\"\n                 \" */\\n\"\n                 \"proto.$package_dot$$service_name$$is_promise$Client =\\n\"\n                 \"    function(hostname, credentials, options) {\\n\"\n                 \"  if (!options) options = {};\\n\");\n  if (vars[\"mode\"] == GetModeVar(Mode::GRPCWEB)) {\n    printer->Print(vars, \"  options.format = '$format$';\\n\\n\");\n  }\n  if (vars[\"mode\"] == GetModeVar(Mode::OP)) {\n    printer->Print(\n        vars,\n        \"  /**\\n\"\n        \"   * @private @const {!grpc.web.$mode$ClientBase} The client\\n\"\n        \"   */\\n\"\n        \"  this.client_ = new grpc.web.$mode$ClientBase(options, \"\n        \"$binary$);\\n\\n\");\n  } else {\n    printer->Print(\n        vars,\n        \"  /**\\n\"\n        \"   * @private @const {!grpc.web.$mode$ClientBase} The client\\n\"\n        \"   */\\n\"\n        \"  this.client_ = new grpc.web.$mode$ClientBase(options);\\n\\n\");\n  }\n  printer->PrintRaw(\n                 \"  /**\\n\"\n                 \"   * @private @const {string} The hostname\\n\"\n                 \"   */\\n\"\n                 \"  this.hostname_ = hostname.replace(/\\\\/+$/, '');\\n\\n\"\n                 \"};\\n\\n\\n\");\n}\n\nvoid PrintMethodDescriptor(Printer* printer, std::map<string, string> vars) {\n  printer->Print(vars,\n                 \"/**\\n\"\n                 \" * @const\\n\"\n                 \" * @type {!grpc.web.MethodDescriptor<\\n\"\n                 \" *   !proto.$in$,\\n\"\n                 \" *   !proto.$out$>}\\n\"\n                 \" */\\n\"\n                 \"const methodDescriptor_$service_name$_$method_name$ = \"\n                 \"new grpc.web.MethodDescriptor(\\n\");\n  printer->Indent();\n  printer->Print(vars,\n                 \"'/$package_dot$$service_name$/$method_name$',\\n\"\n                 \"$method_type$,\\n\"\n                 \"$in_type$,\\n\");\n  printer->Print(vars,\n                 \"$out_type$,\\n\"\n                 \"/**\\n\"\n                 \" * @param {!proto.$in$} request\\n\");\n  printer->Print(\n      (\" * @return {\" + GetSerializeMethodReturnType(vars) + \"}\\n\").c_str());\n  printer->Print(\n      \" */\\n\"\n      \"function(request) {\\n\");\n  printer->Print(\n      (\"  return request.\" + GetSerializeMethodName(vars) + \"();\\n\").c_str());\n  printer->Print(\"},\\n\");\n  printer->Print(\n      vars, (\"$out_type$.\" + GetDeserializeMethodName(vars) + \"\\n\").c_str());\n  printer->Outdent();\n  printer->Print(vars, \");\\n\\n\\n\");\n}\n\nvoid PrintUnaryCall(Printer* printer, std::map<string, string> vars) {\n  printer->Print(\n      vars,\n      \"/**\\n\"\n      \" * @param {!proto.$in$} request The\\n\"\n      \" *     request proto\\n\"\n      \" * @param {?Object<string, string>} metadata User defined\\n\"\n      \" *     call metadata\\n\"\n      \" * @param {function(?grpc.web.RpcError,\"\n      \" ?proto.$out$)}\\n\"\n      \" *     callback The callback function(error, response)\\n\"\n      \" * @return {!grpc.web.ClientReadableStream<!proto.$out$>|undefined}\\n\"\n      \" *     The XHR Node Readable Stream\\n\"\n      \" */\\n\"\n      \"proto.$package_dot$$service_name$Client.prototype.$js_method_name$ =\\n\");\n  printer->Indent();\n  printer->Print(vars,\n                 \"  function(request, metadata, callback) {\\n\"\n                 \"return this.client_.rpcCall(this.hostname_ +\\n\");\n  printer->Indent();\n  printer->Indent();\n  if (vars[\"mode\"] == GetModeVar(Mode::OP)) {\n    printer->Print(vars,\n                   \"'/$$rpc/$package_dot$$service_name$/$method_name$',\\n\");\n  } else {\n    printer->Print(vars, \"'/$package_dot$$service_name$/$method_name$',\\n\");\n  }\n  printer->Print(vars,\n                 \"request,\\n\"\n                 \"metadata || {},\\n\"\n                 \"$method_descriptor$,\\n\"\n                 \"callback);\\n\");\n  printer->Outdent();\n  printer->Outdent();\n  printer->Outdent();\n  printer->Print(\"};\\n\\n\\n\");\n}\n\nvoid PrintPromiseUnaryCall(Printer* printer, std::map<string, string> vars) {\n  printer->Print(vars,\n                 \"/**\\n\"\n                 \" * @param {!proto.$in$} request The\\n\"\n                 \" *     request proto\\n\"\n                 \" * @param {?Object<string, string>=} metadata User defined\\n\"\n                 \" *     call metadata\\n\"\n                 \" * @return {!$promise$<!proto.$out$>}\\n\"\n                 \" *     Promise that resolves to the response\\n\"\n                 \" */\\n\"\n                 \"proto.$package_dot$$service_name$PromiseClient.prototype\"\n                 \".$js_method_name$ =\\n\");\n  printer->Indent();\n  printer->Print(vars,\n                 \"  function(request, metadata) {\\n\"\n                 \"return this.client_.unaryCall(this.hostname_ +\\n\");\n  printer->Indent();\n  printer->Indent();\n  if (vars[\"mode\"] == GetModeVar(Mode::OP)) {\n    printer->Print(vars,\n                   \"'/$$rpc/$package_dot$$service_name$/$method_name$',\\n\");\n  } else {\n    printer->Print(vars, \"'/$package_dot$$service_name$/$method_name$',\\n\");\n  }\n  printer->Print(vars,\n                 \"request,\\n\"\n                 \"metadata || {},\\n\"\n                 \"$method_descriptor$);\\n\");\n  printer->Outdent();\n  printer->Outdent();\n  printer->Outdent();\n  printer->Print(\"};\\n\\n\\n\");\n}\n\nvoid PrintServerStreamingCall(Printer* printer, std::map<string, string> vars) {\n  printer->Print(vars,\n                 \"/**\\n\"\n                 \" * @param {!proto.$in$} request The request proto\\n\"\n                 \" * @param {?Object<string, string>=} metadata User defined\\n\"\n                 \" *     call metadata\\n\"\n                 \" * @return {!grpc.web.ClientReadableStream<!proto.$out$>}\\n\"\n                 \" *     The XHR Node Readable Stream\\n\"\n                 \" */\\n\"\n                 \"proto.$package_dot$$service_name$$client_type$.prototype.\"\n                 \"$js_method_name$ =\\n\");\n  printer->Indent();\n  printer->Print(\n      \"  function(request, metadata) {\\n\"\n      \"return this.client_.serverStreaming(this.hostname_ +\\n\");\n  printer->Indent();\n  printer->Indent();\n  if (vars[\"mode\"] == GetModeVar(Mode::OP)) {\n    printer->Print(vars,\n                   \"'/$$rpc/$package_dot$$service_name$/$method_name$',\\n\");\n  } else {\n    printer->Print(vars, \"'/$package_dot$$service_name$/$method_name$',\\n\");\n  }\n  printer->Print(vars,\n                 \"request,\\n\"\n                 \"metadata || {},\\n\"\n                 \"$method_descriptor$);\\n\");\n  printer->Outdent();\n  printer->Outdent();\n  printer->Outdent();\n  printer->Print(\"};\\n\\n\\n\");\n}\n\nvoid PrintMultipleFilesMode(const FileDescriptor* file, string file_name,\n                            GeneratorContext* context,\n                            std::map<string, string> vars) {\n  std::map<string, string> method_descriptors;\n  bool has_server_streaming = false;\n\n  // Print MethodDescriptor files.\n  for (int i = 0; i < file->service_count(); ++i) {\n    const ServiceDescriptor* service = file->service(i);\n    vars[\"service_name\"] = service->name();\n    vars[\"class_name\"] = LowercaseFirstLetter(service->name());\n\n    for (int method_index = 0; method_index < service->method_count();\n         ++method_index) {\n      const MethodDescriptor* method = service->method(method_index);\n      string method_file_name = Lowercase(service->name()) + \"_\" +\n                                Lowercase(method->name()) +\n                                \"_methoddescriptor.js\";\n      if (method->server_streaming()) {\n        has_server_streaming = true;\n      }\n      std::unique_ptr<ZeroCopyOutputStream> output(\n          context->Open(method_file_name));\n      Printer printer(output.get(), '$');\n\n      vars[\"method_name\"] = method->name();\n      vars[\"in\"] = method->input_type()->full_name();\n      vars[\"in_type\"] = \"proto.\" + method->input_type()->full_name();\n      vars[\"out\"] = method->output_type()->full_name();\n      vars[\"out_type\"] = \"proto.\" + method->output_type()->full_name();\n      vars[\"method_type\"] = method->server_streaming()\n                                ? \"grpc.web.MethodType.SERVER_STREAMING\"\n                                : \"grpc.web.MethodType.UNARY\";\n\n      PrintMethodDescriptorFile(&printer, vars);\n      method_descriptors[service->name() + \".\" + method->name()] =\n          \"proto.\" + vars[\"package_dot\"] + vars[\"class_name\"] + \".\" +\n          vars[\"method_name\"] + \"MethodDescriptor\";\n    }\n  }\n\n  std::unique_ptr<ZeroCopyOutputStream> output1(\n      context->Open(file_name + \"_client_pb.js\"));\n  Printer printer1(output1.get(), '$');\n  std::unique_ptr<ZeroCopyOutputStream> output2(\n      context->Open(file_name + \"_promise_client_pb.js\"));\n  Printer printer2(output2.get(), '$');\n\n  PrintFileHeader(&printer1, vars);\n  PrintFileHeader(&printer2, vars);\n\n  // Print the Promise and callback client.\n  for (int i = 0; i < file->service_count(); ++i) {\n    const ServiceDescriptor* service = file->service(i);\n    vars[\"service_name\"] = service->name();\n    printer1.Print(vars,\n                   \"goog.provide('proto.$package_dot$$service_name$\"\n                   \"Client');\\n\\n\");\n    printer2.Print(vars,\n                   \"goog.provide('proto.$package_dot$$service_name$\"\n                   \"PromiseClient');\\n\\n\");\n  }\n\n  if (vars[\"promise\"] == GRPC_PROMISE) {\n    printer2.Print(vars, \"goog.require('grpc.web.promise');\\n\");\n  }\n  std::map<string, string>::iterator it;\n  for (it = method_descriptors.begin(); it != method_descriptors.end(); it++) {\n    vars[\"import_mtd\"] = it->second;\n    printer1.Print(vars, \"goog.require('$import_mtd$');\\n\");\n    printer2.Print(vars, \"goog.require('$import_mtd$');\\n\");\n  }\n  printer1.Print(vars, \"goog.require('grpc.web.$mode$ClientBase');\\n\");\n  printer1.Print(vars, \"goog.require('grpc.web.ClientReadableStream');\\n\");\n  printer1.Print(vars, \"goog.require('grpc.web.RpcError');\\n\");\n  printer2.Print(vars, \"goog.require('grpc.web.$mode$ClientBase');\\n\");\n  if (has_server_streaming) {\n    printer2.Print(vars, \"goog.require('grpc.web.ClientReadableStream');\\n\");\n  }\n\n  PrintClosureDependencies(&printer1, file);\n  PrintClosureDependencies(&printer2, file);\n\n  printer1.Print(vars, \"\\ngoog.requireType('grpc.web.ClientOptions');\\n\");\n  printer2.Print(vars, \"\\ngoog.requireType('grpc.web.ClientOptions');\\n\");\n\n  printer1.Print(\"\\n\\n\\n\");\n  printer2.Print(\"\\n\\n\\n\");\n  printer1.Print(\"goog.scope(function() {\\n\\n\");\n  printer2.Print(\"goog.scope(function() {\\n\\n\");\n\n  for (int service_index = 0; service_index < file->service_count();\n       ++service_index) {\n    const ServiceDescriptor* service = file->service(service_index);\n    vars[\"service_name\"] = service->name();\n    PrintServiceConstructor(&printer1, vars, false);\n    PrintServiceConstructor(&printer2, vars, true);\n\n    for (int method_index = 0; method_index < service->method_count();\n         ++method_index) {\n      const MethodDescriptor* method = service->method(method_index);\n      const Descriptor* input_type = method->input_type();\n      const Descriptor* output_type = method->output_type();\n      vars[\"js_method_name\"] = LowercaseFirstLetter(method->name());\n      vars[\"method_name\"] = method->name();\n      vars[\"in\"] = input_type->full_name();\n      vars[\"out\"] = output_type->full_name();\n      vars[\"method_descriptor\"] =\n          method_descriptors[service->name() + \".\" + method->name()];\n      vars[\"in_type\"] = \"proto.\" + input_type->full_name();\n      vars[\"out_type\"] = \"proto.\" + output_type->full_name();\n\n      // Client streaming is not supported yet\n      if (!method->client_streaming()) {\n        if (method->server_streaming()) {\n          vars[\"method_type\"] = \"grpc.web.MethodType.SERVER_STREAMING\";\n          vars[\"client_type\"] = \"Client\";\n          PrintServerStreamingCall(&printer1, vars);\n          vars[\"client_type\"] = \"PromiseClient\";\n          PrintServerStreamingCall(&printer2, vars);\n        } else {\n          vars[\"method_type\"] = \"grpc.web.MethodType.UNARY\";\n          PrintUnaryCall(&printer1, vars);\n          PrintPromiseUnaryCall(&printer2, vars);\n        }\n      }\n    }\n  }\n  printer1.Print(\"}); // goog.scope\\n\\n\");\n  printer2.Print(\"}); // goog.scope\\n\\n\");\n}\n\nvoid PrintClosureES6Imports(Printer* printer, const FileDescriptor* file,\n                            string package_dot) {\n  for (int i = 0; i < file->service_count(); ++i) {\n    const ServiceDescriptor* service = file->service(i);\n\n    string service_namespace = \"proto.\" + package_dot + service->name();\n    printer->Print(\n        \"import $service_name$Client_import from 'goog:$namespace$';\\n\",\n        \"service_name\", service->name(), \"namespace\",\n        service_namespace + \"Client\");\n    printer->Print(\n        \"import $service_name$PromiseClient_import from 'goog:$namespace$';\\n\",\n        \"service_name\", service->name(), \"namespace\",\n        service_namespace + \"PromiseClient\");\n  }\n\n  printer->Print(\"\\n\\n\\n\");\n}\n\nvoid PrintGrpcWebClosureES6File(Printer* printer, const FileDescriptor* file) {\n  string package_dot = file->package().empty() ? \"\" : file->package() + \".\";\n\n  printer->Print(\n      \"/**\\n\"\n      \" * @fileoverview gRPC-Web generated client stub for '$file$'\\n\"\n      \" */\\n\"\n      \"\\n\"\n      \"// Code generated by protoc-gen-grpc-web. DO NOT EDIT.\\n\"\n      \"// versions:\\n\"\n      \"// \\tprotoc-gen-grpc-web v$version$\\n\"\n      \"// \\tprotoc              v$protoc_version$\\n\"\n      \"// source: $source_file$\\n\"\n      \"\\n\"\n      \"\\n\",\n      \"file\", file->name());\n\n  PrintClosureES6Imports(printer, file, package_dot);\n\n  for (int i = 0; i < file->service_count(); ++i) {\n    const ServiceDescriptor* service = file->service(i);\n\n    string service_namespace = \"proto.\" + package_dot + service->name();\n    printer->Print(\"export const $name$Client = $name$Client_import;\\n\", \"name\",\n                   service->name());\n    printer->Print(\n        \"export const $name$PromiseClient = $name$PromiseClient_import;\\n\",\n        \"name\", service->name());\n  }\n}\n\nclass GeneratorOptions {\n public:\n  GeneratorOptions();\n\n  bool ParseFromOptions(const string& parameter, string* error);\n  bool ParseFromOptions(const std::vector<std::pair<string, string>>& options,\n                        string* error);\n\n  // Returns the name of the output file for |proto_file|.\n  string OutputFile(const string& proto_file) const;\n\n  string mode() const { return mode_; }\n  string plugins() const { return plugins_; }\n  ImportStyle import_style() const { return import_style_; }\n  bool generate_dts() const { return generate_dts_; }\n  bool generate_closure_es6() const { return generate_closure_es6_; }\n  bool multiple_files() const { return multiple_files_; }\n  bool goog_promise() const { return goog_promise_; }\n\n private:\n  string file_name_;\n  string mode_;\n  string plugins_;\n  ImportStyle import_style_;\n  bool generate_dts_;\n  bool generate_closure_es6_;\n  bool multiple_files_;\n  bool goog_promise_;\n};\n\nGeneratorOptions::GeneratorOptions()\n    : file_name_(\"\"),\n      mode_(\"\"),\n      plugins_(\"\"),\n      import_style_(ImportStyle::CLOSURE),\n      generate_dts_(false),\n      generate_closure_es6_(false),\n      multiple_files_(false),\n      goog_promise_(false) {}\n\nbool GeneratorOptions::ParseFromOptions(const string& parameter,\n                                        string* error) {\n  std::vector<std::pair<string, string>> options;\n  ParseGeneratorParameter(parameter, &options);\n  return ParseFromOptions(options, error);\n}\n\nbool GeneratorOptions::ParseFromOptions(\n    const std::vector<std::pair<string, string>>& options, string* error) {\n  for (const std::pair<string, string>& option : options) {\n    if (\"out\" == option.first) {\n      file_name_ = option.second;\n    } else if (\"mode\" == option.first) {\n      mode_ = option.second;\n    } else if (\"import_style\" == option.first) {\n      if (\"closure\" == option.second) {\n        import_style_ = ImportStyle::CLOSURE;\n      } else if (\"experimental_closure_es6\" == option.second) {\n        import_style_ = ImportStyle::CLOSURE;\n        generate_closure_es6_ = true;\n      } else if (\"commonjs\" == option.second) {\n        import_style_ = ImportStyle::COMMONJS;\n      } else if (\"commonjs+dts\" == option.second) {\n        import_style_ = ImportStyle::COMMONJS;\n        generate_dts_ = true;\n      } else if (\"typescript\" == option.second) {\n        import_style_ = ImportStyle::TYPESCRIPT;\n        generate_dts_ = true;\n      } else {\n        *error = \"options: invalid import_style - \" + option.second;\n        return false;\n      }\n    } else if (\"multiple_files\" == option.first) {\n      multiple_files_ = \"True\" == option.second;\n    } else if (\"plugins\" == option.first) {\n      plugins_ = option.second;\n    } else if (\"goog_promise\" == option.first) {\n      goog_promise_ = \"True\" == option.second;\n    } else {\n      *error = \"unsupported option: \" + option.first;\n      return false;\n    }\n  }\n\n  if (mode_.empty()) {\n    *error = \"options: mode is required\";\n    return false;\n  }\n\n  return true;\n}\n\nstring GeneratorOptions::OutputFile(const string& proto_file) const {\n  if (ImportStyle::TYPESCRIPT == import_style()) {\n    // Never use the value from the 'out' option when generating TypeScript.\n    string directory;\n    string basename;\n    PathSplit(proto_file, &directory, &basename);\n    return directory + UppercaseFirstLetter(StripProto(basename)) +\n           \"ServiceClientPb.ts\";\n  }\n  if (!file_name_.empty()) {\n    return file_name_;\n  }\n  return StripProto(proto_file) + \"_grpc_web_pb.js\";\n}\n\nclass GrpcCodeGenerator : public CodeGenerator {\n public:\n  GrpcCodeGenerator() {}\n  ~GrpcCodeGenerator() override {}\n\n  uint64_t GetSupportedFeatures() const override {\n    // Code generators must explicitly support proto3 optional.\n    return CodeGenerator::FEATURE_PROTO3_OPTIONAL | CodeGenerator::FEATURE_SUPPORTS_EDITIONS;\n  }\n\n  // Keep synced with protoc-gen-js: https://github.com/protocolbuffers/protobuf-javascript/blob/861c8020a5c0cba9b7cdf915dffde96a4421a1f4/generator/js_generator.h#L157-L158\n  Edition GetMinimumEdition() const override { return Edition::EDITION_PROTO2; }\n  Edition GetMaximumEdition() const override { return Edition::EDITION_2023; }\n\n  bool Generate(const FileDescriptor* file, const string& parameter,\n                GeneratorContext* context, string* error) const override {\n    GeneratorOptions generator_options;\n    if (!generator_options.ParseFromOptions(parameter, error)) {\n      return false;\n    }\n\n    std::map<string, string> vars;\n    std::map<string, string> method_descriptors;\n    string package = file->package();\n    vars[\"package\"] = package;\n    vars[\"package_dot\"] = package.empty() ? \"\" : package + '.';\n    vars[\"promise\"] = \"Promise\";\n    vars[\"plugins\"] = generator_options.plugins();\n\n    if (\"binary\" == generator_options.mode()) {\n      vars[\"mode\"] = GetModeVar(Mode::OP);\n      vars[\"binary\"] = \"true\";\n    } else if (\"grpcweb\" == generator_options.mode()) {\n      vars[\"mode\"] = GetModeVar(Mode::GRPCWEB);\n      vars[\"format\"] = \"binary\";\n    } else if (\"grpcwebtext\" == generator_options.mode()) {\n      vars[\"mode\"] = GetModeVar(Mode::GRPCWEB);\n      vars[\"format\"] = \"text\";\n    } else if (\"jspb\" == generator_options.mode()) {\n      vars[\"mode\"] = GetModeVar(Mode::OP);\n      vars[\"binary\"] = \"false\";\n      if (generator_options.goog_promise()) {\n        vars[\"promise\"] = GRPC_PROMISE;\n      }\n    } else {\n      *error = \"options: invalid mode - \" + generator_options.mode();\n      return false;\n    }\n\n    if (generator_options.generate_dts()) {\n      string proto_dts_file_name = StripProto(file->name()) + \"_pb.d.ts\";\n      std::unique_ptr<ZeroCopyOutputStream> proto_dts_output(\n          context->Open(proto_dts_file_name));\n      Printer proto_dts_printer(proto_dts_output.get(), '$');\n      PrintProtoDtsFile(&proto_dts_printer, file);\n    }\n\n    if (!file->service_count()) {\n      // No services, nothing to do.\n      return true;\n    }\n\n    vars[\"version\"]        = GRPC_WEB_VERSION;\n    vars[\"protoc_version\"] = GetProtocVersion(context);\n    vars[\"source_file\"]    = file->name();\n\n    string file_name = generator_options.OutputFile(file->name());\n    if (generator_options.multiple_files() &&\n        ImportStyle::CLOSURE == generator_options.import_style()) {\n      PrintMultipleFilesMode(file, file_name, context, vars);\n      return true;\n    }\n\n    std::unique_ptr<ZeroCopyOutputStream> output(context->Open(file_name));\n    Printer printer(output.get(), '$');\n    PrintFileHeader(&printer, vars);\n\n    if (ImportStyle::TYPESCRIPT == generator_options.import_style()) {\n      PrintTypescriptFile(&printer, file, vars);\n      return true;\n    }\n\n    for (int i = 0; i < file->service_count(); ++i) {\n      const ServiceDescriptor* service = file->service(i);\n      vars[\"service_name\"] = service->name();\n      switch (generator_options.import_style()) {\n        case ImportStyle::CLOSURE:\n          printer.Print(\n              vars,\n              \"goog.provide('proto.$package_dot$$service_name$Client');\\n\");\n          printer.Print(vars,\n                        \"goog.provide('proto.$package_dot$$service_name$\"\n                        \"PromiseClient');\\n\");\n          break;\n        case ImportStyle::COMMONJS:\n          break;\n        case ImportStyle::TYPESCRIPT:\n          break;\n      }\n    }\n    printer.Print(\"\\n\");\n\n    switch (generator_options.import_style()) {\n      case ImportStyle::CLOSURE:\n        if (vars[\"promise\"] == GRPC_PROMISE) {\n          printer.Print(vars, \"goog.require('grpc.web.promise');\\n\");\n        }\n        printer.Print(vars, \"goog.require('grpc.web.MethodDescriptor');\\n\");\n        printer.Print(vars, \"goog.require('grpc.web.MethodType');\\n\");\n        printer.Print(vars, \"goog.require('grpc.web.$mode$ClientBase');\\n\");\n        printer.Print(vars, \"goog.require('grpc.web.AbstractClientBase');\\n\");\n        printer.Print(vars, \"goog.require('grpc.web.ClientReadableStream');\\n\");\n        printer.Print(vars, \"goog.require('grpc.web.RpcError');\\n\");\n\n        PrintClosureDependencies(&printer, file);\n        printer.Print(vars, \"\\ngoog.requireType('grpc.web.ClientOptions');\\n\");\n        printer.Print(\"\\n\\n\\n\");\n        printer.Print(\"goog.scope(function() {\\n\\n\");\n        break;\n      case ImportStyle::COMMONJS:\n        printer.Print(vars, \"const grpc = {};\\n\");\n        printer.Print(vars, \"grpc.web = require('grpc-web');\\n\\n\");\n        PrintCommonJsMessagesDeps(&printer, file);\n        break;\n      case ImportStyle::TYPESCRIPT:\n        break;\n    }\n\n    for (int service_index = 0; service_index < file->service_count();\n         ++service_index) {\n      const ServiceDescriptor* service = file->service(service_index);\n      vars[\"service_name\"] = service->name();\n      PrintServiceConstructor(&printer, vars, false);\n      PrintServiceConstructor(&printer, vars, true);\n\n      for (int method_index = 0; method_index < service->method_count();\n           ++method_index) {\n        const MethodDescriptor* method = service->method(method_index);\n        const Descriptor* input_type = method->input_type();\n        const Descriptor* output_type = method->output_type();\n        vars[\"js_method_name\"] = LowercaseFirstLetter(method->name());\n        vars[\"method_name\"] = method->name();\n        vars[\"in\"] = input_type->full_name();\n        vars[\"out\"] = output_type->full_name();\n        vars[\"method_descriptor\"] =\n            \"methodDescriptor_\" + service->name() + \"_\" + method->name();\n\n        // Cross-file ref in CommonJS needs to use the module alias instead\n        // of the global name.\n        if (ImportStyle::COMMONJS == generator_options.import_style() &&\n            input_type->file() != file) {\n          vars[\"in_type\"] = ModuleAlias(input_type->file()->name()) +\n                            GetNestedMessageName(input_type);\n        } else {\n          vars[\"in_type\"] = \"proto.\" + input_type->full_name();\n        }\n        if (ImportStyle::COMMONJS == generator_options.import_style() &&\n            output_type->file() != file) {\n          vars[\"out_type\"] = ModuleAlias(output_type->file()->name()) +\n                             GetNestedMessageName(output_type);\n        } else {\n          vars[\"out_type\"] = \"proto.\" + output_type->full_name();\n        }\n\n        // Client streaming is not supported yet\n        if (!method->client_streaming()) {\n          if (method->server_streaming()) {\n            vars[\"method_type\"] = \"grpc.web.MethodType.SERVER_STREAMING\";\n            PrintMethodDescriptor(&printer, vars);\n            vars[\"client_type\"] = \"Client\";\n            PrintServerStreamingCall(&printer, vars);\n            vars[\"client_type\"] = \"PromiseClient\";\n            PrintServerStreamingCall(&printer, vars);\n          } else {\n            vars[\"method_type\"] = \"grpc.web.MethodType.UNARY\";\n            PrintMethodDescriptor(&printer, vars);\n            PrintUnaryCall(&printer, vars);\n            PrintPromiseUnaryCall(&printer, vars);\n          }\n        }\n      }\n    }\n\n    switch (generator_options.import_style()) {\n      case ImportStyle::CLOSURE:\n        printer.Print(\"}); // goog.scope\\n\\n\");\n        break;\n      case ImportStyle::COMMONJS:\n        if (!vars[\"package\"].empty()) {\n          printer.Print(vars, \"module.exports = proto.$package$;\\n\\n\");\n        } else {\n          printer.Print(vars, \"module.exports = proto;\\n\\n\");\n        }\n        break;\n      case ImportStyle::TYPESCRIPT:\n        break;\n    }\n\n    if (generator_options.generate_dts()) {\n      string grpcweb_dts_file_name =\n          StripProto(file->name()) + \"_grpc_web_pb.d.ts\";\n      string proto_dts_file_name = StripProto(file->name()) + \"_pb.d.ts\";\n\n      std::unique_ptr<ZeroCopyOutputStream> grpcweb_dts_output(\n          context->Open(grpcweb_dts_file_name));\n      Printer grpcweb_dts_printer(grpcweb_dts_output.get(), '$');\n\n      PrintGrpcWebDtsFile(&grpcweb_dts_printer, file);\n    }\n\n    if (generator_options.generate_closure_es6()) {\n      string es6_file_name = StripProto(file->name()) + \".pb.grpc-web.js\";\n\n      std::unique_ptr<ZeroCopyOutputStream> es6_output(\n          context->Open(es6_file_name));\n      Printer es6_printer(es6_output.get(), '$');\n\n      PrintGrpcWebClosureES6File(&es6_printer, file);\n    }\n\n    return true;\n  }\n};\n\n}  // namespace\n}  // namespace web\n}  // namespace grpc\n\nint main(int argc, char* argv[]) {\n  if (argc == 2 && std::string(argv[1]) == \"--version\") {\n    std::cout << argv[0] << \" \" << grpc::web::GRPC_WEB_VERSION << std::endl;\n    return 0;\n  }\n\n  grpc::web::GrpcCodeGenerator generator;\n  PluginMain(argc, argv, &generator);\n  return 0;\n}\n"
  },
  {
    "path": "javascript/net/grpc/web/generictransportinterface.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n/**\n * @fileoverview gRPC-Web generic transport interface\n *\n * This class provides an abstraction for the underlying transport\n * implementation underneath the ClientReadableStream layer.\n *\n * @author stanleycheung@google.com (Stanley Cheung)\n */\ngoog.module('grpc.web.GenericTransportInterface');\n\ngoog.module.declareLegacyNamespace();\n\n\nconst NodeReadableStream = goog.require('goog.net.streams.NodeReadableStream');\nconst XhrIo = goog.require('goog.net.XhrIo');\n\n\n/**\n * @typedef {{\n *   nodeReadableStream: (?NodeReadableStream|undefined),\n *   xhr: (?XhrIo|undefined),\n * }}\n */\nexports.GenericTransportInterface;\n"
  },
  {
    "path": "javascript/net/grpc/web/grpcwebclientbase.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n/**\n * @fileoverview gRPC browser client library.\n *\n * Base class for gRPC Web JS clients using the application/grpc-web wire\n * format\n *\n * @author stanleycheung@google.com (Stanley Cheung)\n */\ngoog.module('grpc.web.GrpcWebClientBase');\n\ngoog.module.declareLegacyNamespace();\n\n\nconst ClientOptions = goog.requireType('grpc.web.ClientOptions');\nconst ClientReadableStream = goog.require('grpc.web.ClientReadableStream');\nconst ClientUnaryCallImpl = goog.require('grpc.web.ClientUnaryCallImpl');\nconst GrpcWebClientReadableStream = goog.require('grpc.web.GrpcWebClientReadableStream');\nconst HttpCors = goog.require('goog.net.rpc.HttpCors');\nconst MethodDescriptor = goog.requireType('grpc.web.MethodDescriptor');\nconst Request = goog.require('grpc.web.Request');\nconst RpcError = goog.require('grpc.web.RpcError');\nconst StatusCode = goog.require('grpc.web.StatusCode');\nconst XhrIo = goog.require('goog.net.XhrIo');\nconst googCrypt = goog.require('goog.crypt.base64');\nconst {AbstractClientBase, PromiseCallOptions, getHostname} = goog.require('grpc.web.AbstractClientBase');\nconst {Status} = goog.require('grpc.web.Status');\nconst {StreamInterceptor, UnaryInterceptor} = goog.require('grpc.web.Interceptor');\nconst {toObject} = goog.require('goog.collections.maps');\n\n\n\n/**\n * Base class for gRPC web client using the application/grpc-web wire format\n * @implements {AbstractClientBase}\n * @unrestricted\n */\nclass GrpcWebClientBase {\n  /**\n   * @param {!ClientOptions=} options\n   * @param {!XhrIo=} xhrIo\n   */\n  constructor(options = {}, xhrIo = undefined) {\n    /**\n     * @const\n     * @private {string}\n     */\n    this.format_ =\n        options.format || goog.getObjectByName('format', options) || 'text';\n\n    /**\n     * @const\n     * @private {boolean}\n     */\n    this.suppressCorsPreflight_ = options.suppressCorsPreflight ||\n        goog.getObjectByName('suppressCorsPreflight', options) || false;\n\n    /**\n     * @const\n     * @private {boolean}\n     */\n    this.withCredentials_ = options.withCredentials ||\n        goog.getObjectByName('withCredentials', options) || false;\n\n    /**\n     * @const {!Array<!StreamInterceptor>}\n     * @private\n     */\n    this.streamInterceptors_ = options.streamInterceptors ||\n        goog.getObjectByName('streamInterceptors', options) || [];\n\n    /**\n     * @const {!Array<!UnaryInterceptor>}\n     * @private\n     */\n    this.unaryInterceptors_ = options.unaryInterceptors ||\n        goog.getObjectByName('unaryInterceptors', options) || [];\n\n    /** @const @private {?XhrIo} */\n    this.xhrIo_ = xhrIo || null;\n  }\n\n  /**\n   * @override\n   * @export\n   */\n  rpcCall(method, requestMessage, metadata, methodDescriptor, callback) {\n    const hostname = getHostname(method, methodDescriptor);\n    const invoker = GrpcWebClientBase.runInterceptors_(\n        (request) => this.startStream_(request, hostname),\n        this.streamInterceptors_);\n    const stream = /** @type {!ClientReadableStream<?>} */ (invoker.call(\n        this, methodDescriptor.createRequest(requestMessage, metadata)));\n    GrpcWebClientBase.setCallback_(stream, callback, false);\n    return new ClientUnaryCallImpl(stream);\n  }\n\n  /**\n   * @param {string} method The method to invoke\n   * @param {REQUEST} requestMessage The request proto\n   * @param {!Object<string, string>} metadata User defined call metadata\n   * @param {!MethodDescriptor<REQUEST, RESPONSE>} methodDescriptor\n   * @param {?PromiseCallOptions=} options Options for the call\n   * @return {!Promise<RESPONSE>}\n   * @template REQUEST, RESPONSE\n   */\n  thenableCall(\n      method, requestMessage, metadata, methodDescriptor, options = {}) {\n    const hostname = getHostname(method, methodDescriptor);\n    const signal = options && options.signal;\n    const initialInvoker = (request) => new Promise((resolve, reject) => {\n      // If the signal is already aborted, immediately reject the promise\n      // and don't issue the call.\n      if (signal && signal.aborted) {\n        const error = new RpcError(StatusCode.CANCELLED, 'Aborted');\n        error.cause = signal.reason;\n        reject(error);\n        return;\n      }\n\n      const stream = this.startStream_(request, hostname);\n      let unaryMetadata;\n      let unaryStatus;\n      let unaryMsg;\n      GrpcWebClientBase.setCallback_(\n          stream,\n          (error, response, status, metadata, unaryResponseReceived) => {\n            if (error) {\n              reject(error);\n            } else if (unaryResponseReceived) {\n              unaryMsg = response;\n            } else if (status) {\n              unaryStatus = status;\n            } else if (metadata) {\n              unaryMetadata = metadata;\n            } else {\n              resolve(request.getMethodDescriptor().createUnaryResponse(\n                  unaryMsg, unaryMetadata, unaryStatus));\n            }\n          },\n          true);\n\n      // Wire up cancellation from the abort signal, if any.\n      if (signal) {\n        signal.addEventListener('abort', () => {\n          stream.cancel();\n\n          const error = new RpcError(StatusCode.CANCELLED, 'Aborted');\n          error.cause = /** @type {!AbortSignal} */ (signal).reason;\n          reject(error);\n        });\n      }\n    });\n    const invoker = GrpcWebClientBase.runInterceptors_(\n        initialInvoker, this.unaryInterceptors_);\n    const unaryResponse = /** @type {!Promise<?>} */ (invoker.call(\n        this, methodDescriptor.createRequest(requestMessage, metadata)));\n    return unaryResponse.then((response) => response.getResponseMessage());\n  }\n\n  /**\n   * @export\n   * @param {string} method The method to invoke\n   * @param {REQUEST} requestMessage The request proto\n   * @param {!Object<string, string>} metadata User defined call metadata\n   * @param {!MethodDescriptor<REQUEST, RESPONSE>} methodDescriptor Information\n   *     of this RPC method\n   * @param {?PromiseCallOptions=} options Options for the call\n   * @return {!Promise<RESPONSE>}\n   * @template REQUEST, RESPONSE\n   */\n  unaryCall(method, requestMessage, metadata, methodDescriptor, options = {}) {\n    return /** @type {!Promise<RESPONSE>}*/ (this.thenableCall(\n        method, requestMessage, metadata, methodDescriptor, options));\n  }\n\n  /**\n   * @override\n   * @export\n   */\n  serverStreaming(method, requestMessage, metadata, methodDescriptor) {\n    const hostname = getHostname(method, methodDescriptor);\n    const invoker = GrpcWebClientBase.runInterceptors_(\n        (request) => this.startStream_(request, hostname),\n        this.streamInterceptors_);\n    return /** @type {!ClientReadableStream<?>} */ (invoker.call(\n        this, methodDescriptor.createRequest(requestMessage, metadata)));\n  }\n\n  /**\n   * @private\n   * @template REQUEST, RESPONSE\n   * @param {!Request<REQUEST, RESPONSE>} request\n   * @param {string} hostname\n   * @return {!ClientReadableStream<RESPONSE>}\n   */\n  startStream_(request, hostname) {\n    const methodDescriptor = request.getMethodDescriptor();\n    let path = hostname + methodDescriptor.getName();\n\n    const xhr = this.xhrIo_ ? this.xhrIo_ : new XhrIo();\n    xhr.setWithCredentials(this.withCredentials_);\n\n    const genericTransportInterface = {\n      xhr: xhr,\n    };\n    const stream = new GrpcWebClientReadableStream(genericTransportInterface);\n    stream.setResponseDeserializeFn(\n        methodDescriptor.getResponseDeserializeFn());\n\n    const metadata = request.getMetadata();\n    for(const key in metadata) {\n      xhr.headers.set(key, metadata[key]);\n    }\n    this.processHeaders_(xhr);\n    if (this.suppressCorsPreflight_) {\n      const headerObject = toObject(xhr.headers);\n      xhr.headers.clear();\n      path = GrpcWebClientBase.setCorsOverride_(path, headerObject);\n    }\n\n    const requestSerializeFn = methodDescriptor.getRequestSerializeFn();\n    const serialized = requestSerializeFn(request.getRequestMessage());\n    let payload = this.encodeRequest_(serialized);\n    if (this.format_ == 'text') {\n      payload = googCrypt.encodeByteArray(payload);\n    } else if (this.format_ == 'binary') {\n      xhr.setResponseType(XhrIo.ResponseType.ARRAY_BUFFER);\n    }\n    xhr.send(path, 'POST', payload);\n    return stream;\n  }\n\n  /**\n   * @private\n   * @static\n   * @template RESPONSE\n   * @param {!ClientReadableStream<RESPONSE>} stream\n   * @param {function(?RpcError, ?RESPONSE, ?Status=, ?Object<string, string>=, ?boolean)|\n   *     function(?RpcError,?RESPONSE)} callback\n   * @param {boolean} useUnaryResponse Pass true to have the client make\n   * multiple calls to the callback, using (error, response, status,\n   * metadata, unaryResponseReceived) arguments. One of error, status,\n   * metadata, or unaryResponseReceived will be truthy to indicate which piece\n   * of information the client is providing in that call. After the stream\n   * ends, it will call the callback an additional time with all falsy\n   * arguments. Pass false to have the client make one call to the callback\n   * using (error, response) arguments.\n   */\n  static setCallback_(stream, callback, useUnaryResponse) {\n    let isResponseReceived = false;\n    let responseReceived = null;\n    let errorEmitted = false;\n\n    stream.on('data', function(response) {\n      isResponseReceived = true;\n      responseReceived = response;\n    });\n\n    stream.on('error', function(error) {\n      if (error.code != StatusCode.OK && !errorEmitted) {\n        errorEmitted = true;\n        callback(error, null);\n      }\n    });\n\n    stream.on('status', function(status) {\n      if (status.code != StatusCode.OK && !errorEmitted) {\n        errorEmitted = true;\n        callback(\n            {\n              code: status.code,\n              message: status.details,\n              metadata: status.metadata\n            },\n            null);\n      } else if (useUnaryResponse) {\n        callback(null, null, status);\n      }\n    });\n\n    if (useUnaryResponse) {\n      stream.on('metadata', function(metadata) {\n        callback(null, null, null, metadata);\n      });\n    }\n\n    stream.on('end', function() {\n      if (!errorEmitted) {\n        if (!isResponseReceived) {\n          callback({\n            code: StatusCode.UNKNOWN,\n            message: 'Incomplete response',\n          });\n        } else if (useUnaryResponse) {\n          callback(\n            null, responseReceived, null, null,\n            /* unaryResponseReceived= */ true);\n        } else {\n          callback(null, responseReceived);\n        }\n      }\n      if (useUnaryResponse) {\n        callback(null, null);\n      }\n    });\n  }\n\n  /**\n   * Encode the grpc-web request\n   *\n   * @private\n   * @param {!Uint8Array} serialized The serialized proto payload\n   * @return {!Uint8Array} The application/grpc-web padded request\n   */\n  encodeRequest_(serialized) {\n    let len = serialized.length;\n    const bytesArray = [0, 0, 0, 0];\n    const payload = new Uint8Array(5 + len);\n    for (let i = 3; i >= 0; i--) {\n      bytesArray[i] = (len % 256);\n      len = len >>> 8;\n    }\n    payload.set(new Uint8Array(bytesArray), 1);\n    payload.set(serialized, 5);\n    return payload;\n  }\n\n  /**\n   * @private\n   * @param {!XhrIo} xhr The xhr object\n   */\n  processHeaders_(xhr) {\n    if (this.format_ == 'text') {\n      xhr.headers.set('Content-Type', 'application/grpc-web-text');\n      xhr.headers.set('Accept', 'application/grpc-web-text');\n    } else {\n      xhr.headers.set('Content-Type', 'application/grpc-web+proto');\n    }\n    xhr.headers.set('X-User-Agent', 'grpc-web-javascript/0.1');\n    xhr.headers.set('X-Grpc-Web', '1');\n    if (xhr.headers.has('deadline')) {\n      const deadline = Number(xhr.headers.get('deadline'));  // in ms\n      const currentTime = (new Date()).getTime();\n      let timeout = Math.ceil(deadline - currentTime);\n      xhr.headers.delete('deadline');\n      if (timeout === Infinity) {\n        // grpc-timeout header defaults to infinity if not set.\n        timeout = 0;\n      }\n      if (timeout > 0) {\n        xhr.headers.set('grpc-timeout', timeout + 'm');\n        // Also set timeout on the xhr request to terminate the HTTP request\n        // if the server doesn't respond within the deadline. We use 110% of\n        // grpc-timeout for this to allow the server to terminate the connection\n        // with DEADLINE_EXCEEDED rather than terminating it in the Browser, but\n        // at least 1 second in case the user is on a high-latency network.\n        xhr.setTimeoutInterval(Math.max(1000, Math.ceil(timeout * 1.1)));\n      }\n    }\n  }\n\n  /**\n   * @private\n   * @static\n   * @param {string} method The method to invoke\n   * @param {!Object<string,string>} headerObject The xhr headers\n   * @return {string} The URI object or a string path with headers\n   */\n  static setCorsOverride_(method, headerObject) {\n    return /** @type {string} */ (HttpCors.setHttpHeadersWithOverwriteParam(\n        method, HttpCors.HTTP_HEADERS_PARAM_NAME, headerObject));\n  }\n\n  /**\n   * @private\n   * @static\n   * @template REQUEST, RESPONSE\n   * @param {function(!Request<REQUEST,RESPONSE>):\n   *     (!Promise<RESPONSE>|!ClientReadableStream<RESPONSE>)} invoker\n   * @param {!Array<!UnaryInterceptor|!StreamInterceptor>}\n   *     interceptors\n   * @return {function(!Request<REQUEST,RESPONSE>):\n   *     (!Promise<RESPONSE>|!ClientReadableStream<RESPONSE>)}\n   */\n  static runInterceptors_(invoker, interceptors) {\n    return interceptors.reduce((accumulatedInvoker, interceptor) => {\n      return (request) => interceptor.intercept(request, accumulatedInvoker);\n    }, invoker);\n  }\n}\n\n\n\nexports = GrpcWebClientBase;\n"
  },
  {
    "path": "javascript/net/grpc/web/grpcwebclientbase_test.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\ngoog.module('grpc.web.GrpcWebClientBaseTest');\ngoog.setTestOnly('grpc.web.GrpcWebClientBaseTest');\n\nconst ClientReadableStream = goog.require('grpc.web.ClientReadableStream');\nconst ErrorCode = goog.require('goog.net.ErrorCode');\nconst GrpcWebClientBase = goog.require('grpc.web.GrpcWebClientBase');\nconst MethodDescriptor = goog.require('grpc.web.MethodDescriptor');\nconst ReadyState = goog.require('goog.net.XmlHttp.ReadyState');\nconst Request = goog.requireType('grpc.web.Request');\nconst RpcError = goog.require('grpc.web.RpcError');\nconst StatusCode = goog.require('grpc.web.StatusCode');\nconst XhrIo = goog.require('goog.testing.net.XhrIo');\nconst googCrypt = goog.require('goog.crypt.base64');\nconst testSuite = goog.require('goog.testing.testSuite');\nconst {StreamInterceptor} = goog.require('grpc.web.Interceptor');\ngoog.require('goog.testing.jsunit');\n\n// This parses to [ { DATA: [4, 5, 6] }, { TRAILER: \"a: b\" } ]\nconst DEFAULT_RPC_RESPONSE =\n    new Uint8Array([0, 0, 0, 0, 3, 4, 5, 6, 128, 0, 0, 0, 4, 97, 58, 32, 98]);\nconst DEFAULT_RPC_RESPONSE_DATA = [4, 5, 6];\nconst DEFAULT_UNARY_HEADERS =\n    ['Content-Type', 'Accept', 'X-User-Agent', 'X-Grpc-Web'];\nconst DEFAULT_UNARY_HEADER_VALUES = [\n  'application/grpc-web-text',\n  'application/grpc-web-text',\n  'grpc-web-javascript/0.1',\n  '1',\n];\nconst DEFAULT_RESPONSE_HEADERS = {\n  'Content-Type': 'application/grpc-web-text',\n};\n\ntestSuite({\n  async testRpcResponse() {\n    const xhr = new XhrIo();\n    const client = new GrpcWebClientBase(/* options= */ {}, xhr);\n    const methodDescriptor = createMethodDescriptor((bytes) => {\n      assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));\n      return new MockReply('value');\n    });\n\n    const response = await new Promise((resolve, reject) => {\n      client.rpcCall(\n          'url', new MockRequest(), /* metadata= */ {}, methodDescriptor,\n          (error, response) => {\n            assertNull(error);\n            resolve(response);\n          });\n      xhr.simulatePartialResponse(\n          googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),\n          DEFAULT_RESPONSE_HEADERS);\n      xhr.simulateReadyStateChange(ReadyState.COMPLETE);\n    });\n\n    assertEquals('value', response.data);\n    const headers = /** @type {!Object} */ (xhr.getLastRequestHeaders());\n    assertElementsEquals(DEFAULT_UNARY_HEADERS, Object.keys(headers));\n    assertElementsEquals(DEFAULT_UNARY_HEADER_VALUES, Object.values(headers));\n  },\n\n  async testRpcFalsyResponse_ForNonProtobufDescriptor() {\n    const xhr = new XhrIo();\n    const client = new GrpcWebClientBase(/* options= */ {}, xhr);\n    const methodDescriptor = createMethodDescriptor((bytes) => {\n      assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));\n      return 0;\n    });\n\n    const response = await new Promise((resolve, reject) => {\n      client.rpcCall(\n          'url', new MockRequest(), /* metadata= */ {}, methodDescriptor,\n          (error, response) => {\n            assertNull(error);\n            resolve(response);\n          });\n      xhr.simulatePartialResponse(\n          googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),\n          DEFAULT_RESPONSE_HEADERS);\n      xhr.simulateReadyStateChange(ReadyState.COMPLETE);\n    });\n\n    assertEquals(0, response);\n    const headers = /** @type {!Object} */ (xhr.getLastRequestHeaders());\n    assertElementsEquals(DEFAULT_UNARY_HEADERS, Object.keys(headers));\n    assertElementsEquals(DEFAULT_UNARY_HEADER_VALUES, Object.values(headers));\n  },\n\n  async testRpcResponseThenableCall() {\n    const xhr = new XhrIo();\n    const client = new GrpcWebClientBase(/* options= */ {}, xhr);\n    const methodDescriptor = createMethodDescriptor((bytes) => {\n      assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));\n      return new MockReply('value');\n    });\n\n    const responsePromise = client.thenableCall(\n      'url', new MockRequest(), /* metadata= */ {}, methodDescriptor);\n    xhr.simulatePartialResponse(\n        googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),\n        DEFAULT_RESPONSE_HEADERS);\n    xhr.simulateReadyStateChange(ReadyState.COMPLETE);\n    const response = await responsePromise;\n\n    assertEquals('value', /** @type {!MockReply} */ (response).data);\n    const headers = /** @type {!Object} */ (xhr.getLastRequestHeaders());\n    assertElementsEquals(DEFAULT_UNARY_HEADERS, Object.keys(headers));\n    assertElementsEquals(DEFAULT_UNARY_HEADER_VALUES, Object.values(headers));\n  },\n\n  async testRpcFalsyResponseThenableCall_ForNonProtobufDescriptor() {\n    const xhr = new XhrIo();\n    const client = new GrpcWebClientBase(/* options= */ {}, xhr);\n    const methodDescriptor = createMethodDescriptor((bytes) => {\n      assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));\n      return 0;\n    });\n\n    const responsePromise = client.thenableCall(\n      'url', new MockRequest(), /* metadata= */ {}, methodDescriptor);\n    xhr.simulatePartialResponse(\n        googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),\n        DEFAULT_RESPONSE_HEADERS);\n    xhr.simulateReadyStateChange(ReadyState.COMPLETE);\n    const response = await responsePromise;\n\n    assertEquals(0, response);\n    const headers = /** @type {!Object} */ (xhr.getLastRequestHeaders());\n    assertElementsEquals(DEFAULT_UNARY_HEADERS, Object.keys(headers));\n    assertElementsEquals(DEFAULT_UNARY_HEADER_VALUES, Object.values(headers));\n  },\n\n\n  async testCancelledThenableCall() {\n    const xhr = new XhrIo();\n    const client = new GrpcWebClientBase(/* options= */ {}, xhr);\n    const methodDescriptor = createMethodDescriptor((bytes) => {\n      assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));\n      return 0;\n    });\n\n    const abortController = new AbortController();\n    const signal = abortController.signal;\n    const responsePromise = client.thenableCall(\n        'url', new MockRequest(), /* metadata= */ {}, methodDescriptor,\n        {signal});\n    abortController.abort();\n\n    const error = await assertRejects(responsePromise);\n    assertTrue(error instanceof RpcError);\n    assertEquals(StatusCode.CANCELLED, /** @type {!RpcError} */ (error).code);\n    assertEquals('Aborted', /** @type {!RpcError} */ (error).message);\n    // Default abort reason if none provided.\n    const cause = /** @type {!RpcError} */ (error).cause;\n    assertTrue(cause instanceof Error);\n    assertEquals('AbortError', /** @type {!Error} */ (cause).name);\n    assertEquals(ErrorCode.ABORT, xhr.getLastErrorCode());\n  },\n\n  async testCancelledThenableCallWithReason() {\n    const xhr = new XhrIo();\n    const client = new GrpcWebClientBase(/* options= */ {}, xhr);\n    const methodDescriptor = createMethodDescriptor((bytes) => {\n      assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));\n      return 0;\n    });\n\n    const abortController = new AbortController();\n    const signal = abortController.signal;\n    const responsePromise = client.thenableCall(\n        'url', new MockRequest(), /* metadata= */ {}, methodDescriptor,\n        {signal});\n    abortController.abort('cancelling');\n\n    const error = await assertRejects(responsePromise);\n    assertTrue(error instanceof RpcError);\n    assertEquals(StatusCode.CANCELLED, /** @type {!RpcError} */ (error).code);\n    assertEquals('Aborted', /** @type {!RpcError} */ (error).message);\n    // Abort reason forwarded as cause.\n    const cause = /** @type {!RpcError} */ (error).cause;\n    assertEquals('cancelling', cause);\n    assertEquals(ErrorCode.ABORT, xhr.getLastErrorCode());\n  },\n\n  async testDeadline() {\n    const xhr = new XhrIo();\n    const client = new GrpcWebClientBase(/* options= */ {}, xhr);\n    const methodDescriptor = createMethodDescriptor((bytes) => new MockReply());\n\n    const deadline = new Date();\n    deadline.setSeconds(deadline.getSeconds() + 1);\n    await new Promise((resolve, reject) => {\n      client.rpcCall(\n          'url', new MockRequest(), {'deadline': deadline.getTime().toString()},\n          methodDescriptor, (error, response) => {\n            assertNull(error);\n            resolve();\n          });\n      xhr.simulatePartialResponse(\n          googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),\n          DEFAULT_RESPONSE_HEADERS);\n      xhr.simulateReadyStateChange(ReadyState.COMPLETE);\n    });\n    const headers = /** @type {!Object} */ (xhr.getLastRequestHeaders());\n    const headersWithDeadline = [...DEFAULT_UNARY_HEADERS, 'grpc-timeout'];\n    assertElementsEquals(headersWithDeadline, Object.keys(headers));\n  },\n\n  async testRpcError() {\n    const xhr = new XhrIo();\n    const client = new GrpcWebClientBase(/* options= */ {}, xhr);\n    const methodDescriptor = createMethodDescriptor((bytes) => new MockReply());\n\n    const error = await new Promise((resolve, reject) => {\n      client.rpcCall(\n          'urlurl', new MockRequest(), /* metadata= */ {}, methodDescriptor,\n          (error, response) => {\n            assertNull(response);\n            resolve(error);\n          });\n      // This decodes to \"grpc-status: 3\"\n      xhr.simulatePartialResponse(\n          googCrypt.encodeByteArray(new Uint8Array([\n            128, 0,   0,  0,   14,  103, 114, 112, 99, 45,\n            115, 116, 97, 116, 117, 115, 58,  32,  51,\n          ])),\n          DEFAULT_RESPONSE_HEADERS);\n    });\n    assertTrue(error instanceof RpcError);\n    assertEquals(3, error.code);\n  },\n\n  async testRpcDeserializationError() {\n    const xhr = new XhrIo();\n    const client = new GrpcWebClientBase(/* options= */ {}, xhr);\n\n    const responseDeserializeFn = () => {\n      throw new Error('Decoding error :)');\n    };\n    const methodDescriptor = createMethodDescriptor(responseDeserializeFn);\n    const error = await new Promise((resolve, reject) => {\n      client.rpcCall(\n          'urlurl', new MockRequest(), /* metadata= */ {}, methodDescriptor,\n          (error, response) => {\n            assertNull(response);\n            resolve(error);\n          });\n      xhr.simulatePartialResponse(\n          googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),\n          DEFAULT_RESPONSE_HEADERS);\n    });\n    assertTrue(error instanceof RpcError);\n    assertEquals(StatusCode.INTERNAL, error.code);\n  },\n\n  async testRpcResponseHeader() {\n    const xhr = new XhrIo();\n    const client = new GrpcWebClientBase(/* options= */ {}, xhr);\n    const methodDescriptor = createMethodDescriptor((bytes) => {\n      assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));\n      return new MockReply('value');\n    });\n\n    const metadata = await new Promise((resolve, reject) => {\n      const call = client.rpcCall(\n          'url', new MockRequest(), /* metadata= */ {}, methodDescriptor,\n          (error, response) => {\n            assertNull(error);\n          });\n      call.on('metadata', (metadata) => {\n        resolve(metadata);\n      });\n      xhr.simulatePartialResponse(\n          googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)), {\n            'Content-Type': 'application/grpc-web-text',\n            'initial-metadata-key': 'initial-metadata-value',\n          });\n      xhr.simulateReadyStateChange(ReadyState.COMPLETE);\n    });\n    assertEquals('initial-metadata-value', metadata['initial-metadata-key']);\n  },\n\n  async testStreamInterceptor() {\n    const xhr = new XhrIo();\n    const interceptor = new StreamResponseInterceptor();\n    const methodDescriptor = createMethodDescriptor((bytes) => {\n      assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));\n      return new MockReply('value');\n    });\n    const client =\n        new GrpcWebClientBase({'streamInterceptors': [interceptor]}, xhr);\n\n    const response = await new Promise((resolve, reject) => {\n      client.rpcCall(\n          'url', new MockRequest(), /* metadata= */ {}, methodDescriptor,\n          (error, response) => {\n            assertNull(error);\n            resolve(response);\n          });\n      xhr.simulatePartialResponse(\n          googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),\n          DEFAULT_RESPONSE_HEADERS);\n      xhr.simulateReadyStateChange(ReadyState.COMPLETE);\n    });\n    assertEquals('Intercepted value', response.data);\n  },\n\n});\n\n/** Mocks a request proto object. */\nclass MockRequest {\n  /**\n   * @param {string=} data\n   */\n  constructor(data = '') {\n    /** @type {string} */\n    this.data = data;\n  }\n}\n\n/** Mocks a response proto object. */\nclass MockReply {\n  /**\n   * @param {string=} data\n   */\n  constructor(data = '') {\n    /** @type {string} */\n    this.data = data;\n  }\n}\n\n/**\n * Typedef for allowed response types.\n *\n * Number is allowed specifically for supporting falsy responses `0`, see:\n * https://github.com/grpc/grpc-web/pull/1025\n *\n * @typedef {!MockReply|number}\n */\nlet AllowedResponseType;\n\n/**\n * @param {function(string): !AllowedResponseType} responseDeSerializeFn\n * @return {!MethodDescriptor<!MockRequest, !AllowedResponseType>}\n */\nfunction createMethodDescriptor(responseDeSerializeFn) {\n  return new MethodDescriptor(\n      /* name= */ '', /* methodType= */ null, MockRequest, MockReply,\n      (request) => [1, 2, 3], responseDeSerializeFn);\n}\n\n\n/**\n * @implements {StreamInterceptor}\n * @unrestricted\n */\nclass StreamResponseInterceptor {\n  constructor() {}\n\n  /**\n   * @override\n   * @template REQUEST, RESPONSE\n   * @param {!Request<REQUEST, RESPONSE>} request\n   * @param {function(!Request<REQUEST,RESPONSE>):\n   *     !ClientReadableStream<RESPONSE>} invoker\n   * @return {!ClientReadableStream<RESPONSE>}\n   */\n  intercept(request, invoker) {\n    return new InterceptedStream(invoker(request));\n  }\n}\n\n/**\n * @implements {ClientReadableStream}\n * @template RESPONSE\n * @final\n */\nclass InterceptedStream {\n  /**\n   * @param {!ClientReadableStream<RESPONSE>} stream\n   */\n  constructor(stream) {\n    /** @const {!ClientReadableStream<RESPONSE>} */\n    this.stream = stream;\n  }\n\n  /**\n   * @override\n   * @param {string} eventType\n   * @param {function(?)} callback\n   * @return {!ClientReadableStream<RESPONSE>}\n   */\n  on(eventType, callback) {\n    if (eventType == 'data') {\n      const newCallback = (response) => {\n        response.data = 'Intercepted ' + response.data;\n        callback(response);\n      };\n      this.stream.on(eventType, newCallback);\n    } else {\n      this.stream.on(eventType, callback);\n    }\n    return this;\n  }\n\n  /**\n   * @override\n   * @return {!ClientReadableStream<RESPONSE>}\n   */\n  cancel() {\n    this.stream.cancel();\n    return this;\n  }\n\n  /**\n   * @override\n   * @param {string} eventType\n   * @param {function(?)} callback\n   * @return {!ClientReadableStream<RESPONSE>}\n   */\n  removeListener(eventType, callback) {\n    this.stream.removeListener(eventType, callback);\n    return this;\n  }\n}\n"
  },
  {
    "path": "javascript/net/grpc/web/grpcwebclientreadablestream.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n/**\n * @fileoverview gRPC web client Readable Stream\n *\n * This class is being returned after a gRPC streaming call has been\n * started. This class provides functionality for user to operates on\n * the stream, e.g. set onData callback, etc.\n *\n * This wraps the underlying goog.net.streams.NodeReadableStream\n *\n * @author stanleycheung@google.com (Stanley Cheung)\n */\ngoog.module('grpc.web.GrpcWebClientReadableStream');\n\ngoog.module.declareLegacyNamespace();\n\n\nconst ClientReadableStream = goog.require('grpc.web.ClientReadableStream');\nconst ErrorCode = goog.require('goog.net.ErrorCode');\nconst EventType = goog.require('goog.net.EventType');\nconst GrpcWebStreamParser = goog.require('grpc.web.GrpcWebStreamParser');\nconst RpcError = goog.require('grpc.web.RpcError');\nconst StatusCode = goog.require('grpc.web.StatusCode');\nconst XhrIo = goog.require('goog.net.XhrIo');\nconst events = goog.require('goog.events');\nconst googCrypt = goog.require('goog.crypt.base64');\nconst googString = goog.require('goog.string');\nconst {GenericTransportInterface} = goog.require('grpc.web.GenericTransportInterface');\nconst {Status} = goog.require('grpc.web.Status');\n\n\n\nconst GRPC_STATUS = 'grpc-status';\nconst GRPC_STATUS_MESSAGE = 'grpc-message';\n\n/** @type {!Array<string>} */\nconst EXCLUDED_RESPONSE_HEADERS =\n    ['content-type', GRPC_STATUS, GRPC_STATUS_MESSAGE];\n\n/**\n * A stream that the client can read from. Used for calls that are streaming\n * from the server side.\n * @template RESPONSE\n * @implements {ClientReadableStream}\n * @final\n * @unrestricted\n */\nclass GrpcWebClientReadableStream {\n  /**\n   * @param {!GenericTransportInterface} genericTransportInterface The\n   *   GenericTransportInterface\n   */\n  constructor(genericTransportInterface) {\n    /**\n     * @const\n     * @private\n     * @type {?XhrIo} The XhrIo object\n     */\n    this.xhr_ = /** @type {?XhrIo} */ (genericTransportInterface.xhr);\n\n    /**\n     * @private\n     * @type {function(?):!RESPONSE|null} The deserialize function for the proto\n     */\n    this.responseDeserializeFn_ = null;\n\n    /**\n     * @const\n     * @private\n     * @type {!Array<function(!RESPONSE)>} The list of data callbacks\n     */\n    this.onDataCallbacks_ = [];\n\n    /**\n     * @const\n     * @private\n     * @type {!Array<function(!Status)>} The list of status callbacks\n     */\n    this.onStatusCallbacks_ = [];\n\n    /**\n     * @const\n     * @private\n     * @type {!Array<function(!Metadata)>} The list of metadata callbacks\n     */\n    this.onMetadataCallbacks_ = [];\n\n    /**\n     * @const\n     * @private\n     * @type {!Array<function(!RpcError)>} The list of error callbacks\n     */\n    this.onErrorCallbacks_ = [];\n\n    /**\n     * @const\n     * @private\n     * @type {!Array<function(...):?>} The list of stream end callbacks\n     */\n    this.onEndCallbacks_ = [];\n\n    /**\n     * @private\n     * @type {boolean} Whether the stream has been aborted\n     */\n    this.aborted_ = false;\n\n    /**\n     * @private\n     * @type {number} The stream parser position\n     */\n    this.pos_ = 0;\n\n    /**\n     * @private\n     * @type {!GrpcWebStreamParser} The grpc-web stream parser\n     * @const\n     */\n    this.parser_ = new GrpcWebStreamParser();\n\n    const self = this;\n    events.listen(this.xhr_, EventType.READY_STATE_CHANGE, function(e) {\n      let contentType = self.xhr_.getStreamingResponseHeader('Content-Type');\n      if (!contentType) return;\n      contentType = contentType.toLowerCase();\n\n      let byteSource;\n      if (googString.startsWith(contentType, 'application/grpc-web-text')) {\n        // Ensure responseText is not null\n        const responseText = self.xhr_.getResponseText() || '';\n        const newPos = responseText.length - responseText.length % 4;\n        const newData = responseText.substr(self.pos_, newPos - self.pos_);\n        if (newData.length == 0) return;\n        self.pos_ = newPos;\n        byteSource = googCrypt.decodeStringToUint8Array(newData);\n      } else if (googString.startsWith(contentType, 'application/grpc')) {\n        byteSource = new Uint8Array(\n            /** @type {!ArrayBuffer} */ (self.xhr_.getResponse()));\n      } else {\n        self.handleError_(\n            new RpcError(StatusCode.UNKNOWN, 'Unknown Content-type received.'));\n        return;\n      }\n      let messages = null;\n      try {\n        messages = self.parser_.parse(byteSource);\n      } catch (err) {\n        self.handleError_(\n            new RpcError(StatusCode.UNKNOWN, 'Error in parsing response body'));\n      }\n      if (messages) {\n        const FrameType = GrpcWebStreamParser.FrameType;\n        for (let i = 0; i < messages.length; i++) {\n          if (FrameType.DATA in messages[i]) {\n            const data = messages[i][FrameType.DATA];\n            if (data) {\n              let isResponseDeserialized = false;\n              let response;\n              try {\n                response = self.responseDeserializeFn_(data);\n                isResponseDeserialized = true;\n              } catch (err) {\n                self.handleError_(new RpcError(\n                    StatusCode.INTERNAL,\n                    `Error when deserializing response data; error: ${err}` +\n                        `, response: ${response}`));\n              }\n              if (isResponseDeserialized) {\n                self.sendDataCallbacks_(response);\n              }\n            }\n          }\n          if (FrameType.TRAILER in messages[i]) {\n            if (messages[i][FrameType.TRAILER].length > 0) {\n              let trailerString = '';\n              for (let pos = 0; pos < messages[i][FrameType.TRAILER].length;\n                   pos++) {\n                trailerString +=\n                    String.fromCharCode(messages[i][FrameType.TRAILER][pos]);\n              }\n              const trailers = self.parseHttp1Headers_(trailerString);\n              let grpcStatusCode = StatusCode.OK;\n              let grpcStatusMessage = '';\n              if (GRPC_STATUS in trailers) {\n                grpcStatusCode =\n                    /** @type {!StatusCode} */ (Number(trailers[GRPC_STATUS]));\n                delete trailers[GRPC_STATUS];\n              }\n              if (GRPC_STATUS_MESSAGE in trailers) {\n                grpcStatusMessage = trailers[GRPC_STATUS_MESSAGE];\n                delete trailers[GRPC_STATUS_MESSAGE];\n              }\n              self.handleError_(\n                  new RpcError(grpcStatusCode, grpcStatusMessage, trailers));\n            }\n          }\n        }\n      }\n    });\n\n    events.listen(this.xhr_, EventType.COMPLETE, function(e) {\n      const lastErrorCode = self.xhr_.getLastErrorCode();\n      let grpcStatusCode = StatusCode.UNKNOWN;\n      let grpcStatusMessage = '';\n      const initialMetadata = /** @type {!Metadata} */ ({});\n\n      // Get response headers with lower case keys.\n      const rawResponseHeaders = self.xhr_.getResponseHeaders();\n      const responseHeaders = {};\n      for (const key in rawResponseHeaders) {\n        if (rawResponseHeaders.hasOwnProperty(key)) {\n          responseHeaders[key.toLowerCase()] = rawResponseHeaders[key];\n        }\n      }\n\n      Object.keys(responseHeaders).forEach((header_) => {\n        if (!(EXCLUDED_RESPONSE_HEADERS.includes(header_))) {\n          initialMetadata[header_] = responseHeaders[header_];\n        }\n      });\n      self.sendMetadataCallbacks_(initialMetadata);\n\n      // There's an XHR level error\n      let xhrStatusCode = -1;\n      if (lastErrorCode != ErrorCode.NO_ERROR) {\n        switch (lastErrorCode) {\n          case ErrorCode.ABORT:\n            grpcStatusCode = StatusCode.ABORTED;\n            break;\n          case ErrorCode.TIMEOUT:\n            grpcStatusCode = StatusCode.DEADLINE_EXCEEDED;\n            break;\n          case ErrorCode.HTTP_ERROR:\n            xhrStatusCode = self.xhr_.getStatus();\n            grpcStatusCode = StatusCode.fromHttpStatus(xhrStatusCode);\n            break;\n          default:\n            grpcStatusCode = StatusCode.UNAVAILABLE;\n        }\n        if (grpcStatusCode == StatusCode.ABORTED && self.aborted_) {\n          return;\n        }\n        let errorMessage = ErrorCode.getDebugMessage(lastErrorCode);\n        if (xhrStatusCode != -1) {\n          errorMessage += ', http status code: ' + xhrStatusCode;\n        }\n\n        self.handleError_(new RpcError(grpcStatusCode, errorMessage));\n        return;\n      }\n\n      let errorEmitted = false;\n\n      // Check whethere there are grpc specific response headers\n      if (GRPC_STATUS in responseHeaders) {\n        grpcStatusCode = /** @type {!StatusCode} */ (\n            Number(responseHeaders[GRPC_STATUS]));\n        if (GRPC_STATUS_MESSAGE in responseHeaders) {\n          grpcStatusMessage = responseHeaders[GRPC_STATUS_MESSAGE];\n        }\n        if (grpcStatusCode != StatusCode.OK) {\n          self.handleError_(new RpcError(\n              grpcStatusCode, grpcStatusMessage || '', responseHeaders));\n          errorEmitted = true;\n        }\n      }\n\n      if (!errorEmitted) {\n        self.sendEndCallbacks_();\n      }\n    });\n  }\n\n  /**\n   * @override\n   * @export\n   */\n  on(eventType, callback) {\n    // TODO(stanleycheung): change eventType to @enum type\n    if (eventType == 'data') {\n      this.onDataCallbacks_.push(callback);\n    } else if (eventType == 'status') {\n      this.onStatusCallbacks_.push(callback);\n    } else if (eventType == 'metadata') {\n      this.onMetadataCallbacks_.push(callback);\n    } else if (eventType == 'end') {\n      this.onEndCallbacks_.push(callback);\n    } else if (eventType == 'error') {\n      this.onErrorCallbacks_.push(callback);\n    }\n    return this;\n  }\n\n  /**\n   * @private\n   * @param {!Array<function(?)>} callbacks the internal list of callbacks\n   * @param {function(?)} callback the callback to remove\n   */\n  removeListenerFromCallbacks_(callbacks, callback) {\n    const index = callbacks.indexOf(callback);\n    if (index > -1) {\n      callbacks.splice(index, 1);\n    }\n  }\n\n  /**\n   * @export\n   * @override\n   */\n  removeListener(eventType, callback) {\n    if (eventType == 'data') {\n      this.removeListenerFromCallbacks_(this.onDataCallbacks_, callback);\n    } else if (eventType == 'status') {\n      this.removeListenerFromCallbacks_(this.onStatusCallbacks_, callback);\n    } else if (eventType == 'metadata') {\n      this.removeListenerFromCallbacks_(this.onMetadataCallbacks_, callback);\n    } else if (eventType == 'end') {\n      this.removeListenerFromCallbacks_(this.onEndCallbacks_, callback);\n    } else if (eventType == 'error') {\n      this.removeListenerFromCallbacks_(this.onErrorCallbacks_, callback);\n    }\n    return this;\n  }\n\n  /**\n   * Register a callbackl to parse the response\n   *\n   * @param {function(?):!RESPONSE} responseDeserializeFn The deserialize\n   *   function for the proto\n   */\n  setResponseDeserializeFn(responseDeserializeFn) {\n    this.responseDeserializeFn_ = responseDeserializeFn;\n  }\n\n  /**\n   * @override\n   * @export\n   */\n  cancel() {\n    this.aborted_ = true;\n    this.xhr_.abort();\n  }\n\n  /**\n   * Parse HTTP headers\n   *\n   * @private\n   * @param {string} str The raw http header string\n   * @return {!Object} The header:value pairs\n   */\n  parseHttp1Headers_(str) {\n    const chunks = str.trim().split('\\r\\n');\n    const headers = {};\n    for (let i = 0; i < chunks.length; i++) {\n      const pos = chunks[i].indexOf(':');\n      headers[chunks[i].substring(0, pos).trim()] =\n          chunks[i].substring(pos + 1).trim();\n    }\n    return headers;\n  }\n\n  /**\n   * A central place to handle errors\n   *\n   * @private\n   * @param {!RpcError} error The error object\n   */\n  handleError_(error) {\n    if (error.code != StatusCode.OK) {\n      this.sendErrorCallbacks_(new RpcError(\n          error.code, decodeURIComponent(error.message || ''), error.metadata));\n    }\n    this.sendStatusCallbacks_(/** @type {!Status} */ ({\n      code: error.code,\n      details: decodeURIComponent(error.message || ''),\n      metadata: error.metadata\n    }));\n  }\n\n  /**\n   * @private\n   * @param {!RESPONSE} data The data to send back\n   */\n  sendDataCallbacks_(data) {\n    for (let i = 0; i < this.onDataCallbacks_.length; i++) {\n      this.onDataCallbacks_[i](data);\n    }\n  }\n\n  /**\n   * @private\n   * @param {!Status} status The status to send back\n   */\n  sendStatusCallbacks_(status) {\n    for (let i = 0; i < this.onStatusCallbacks_.length; i++) {\n      this.onStatusCallbacks_[i](status);\n    }\n  }\n\n  /**\n   * @private\n   * @param {!Metadata} metadata The metadata to send back\n   */\n  sendMetadataCallbacks_(metadata) {\n    for (let i = 0; i < this.onMetadataCallbacks_.length; i++) {\n      this.onMetadataCallbacks_[i](metadata);\n    }\n  }\n\n  /**\n   * @private\n   * @param {!RpcError} error The error to send back\n   */\n  sendErrorCallbacks_(error) {\n    for (let i = 0; i < this.onErrorCallbacks_.length; i++) {\n      this.onErrorCallbacks_[i](error);\n    }\n  }\n\n  /**\n   * @private\n   */\n  sendEndCallbacks_() {\n    for (let i = 0; i < this.onEndCallbacks_.length; i++) {\n      this.onEndCallbacks_[i]();\n    }\n  }\n}\n\n\n\nexports = GrpcWebClientReadableStream;\n"
  },
  {
    "path": "javascript/net/grpc/web/grpcwebstreamparser.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n/**\n * @fileoverview The default grpc-web stream parser\n *\n * The default grpc-web parser decodes the input stream (binary) under the\n * following rules:\n *\n * 1. The wire format looks like:\n *\n *    0x00 <data> 0x80 <trailer>\n *\n *    For details of grpc-web wire format see\n *    https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md\n *\n * 2. Messages will be delivered once each frame is completed. Partial stream\n *    segments are accepted.\n *\n * 3. Example:\n *\n * Incoming data: 0x00 <message1> 0x00 <message2> 0x80 <trailers>\n *\n * Result: [ { 0x00 : <message1 }, { 0x00 : <message2> }, { 0x80 : trailers } ]\n */\ngoog.module('grpc.web.GrpcWebStreamParser');\n\ngoog.module.declareLegacyNamespace();\n\n\nconst StreamParser = goog.require('goog.net.streams.StreamParser');\nconst asserts = goog.require('goog.asserts');\n\n\n\n/**\n * The default grpc-web stream parser.\n * @implements {StreamParser}\n * @final\n */\nclass GrpcWebStreamParser {\n  constructor() {\n    /**\n     * The current error message, if any.\n     * @private {?string}\n     */\n    this.errorMessage_ = null;\n\n    /**\n     * The currently buffered result (parsed messages).\n     * @private {!Array<!Object>}\n     */\n    this.result_ = [];\n\n    /**\n     * The current position in the streamed data.\n     * @private {number}\n     */\n    this.streamPos_ = 0;\n\n    /**\n     * The current parser state.\n     * @private {number}\n     */\n    this.state_ = Parser.State_.INIT;\n\n    /**\n     * The current frame byte being parsed\n     * @private {number}\n     */\n    this.frame_ = 0;\n\n    /**\n     * The length of the proto message being parsed.\n     * @private {number}\n     */\n    this.length_ = 0;\n\n    /**\n     * Count of processed length bytes.\n     * @private {number}\n     */\n    this.countLengthBytes_ = 0;\n\n    /**\n     * Raw bytes of the current message. Uses Uint8Array by default. Falls back\n     * to native array when Uint8Array is unsupported.\n     * @private {?Uint8Array|?Array<number>}\n     */\n    this.messageBuffer_ = null;\n\n    /**\n     * Count of processed message bytes.\n     * @private {number}\n     */\n    this.countMessageBytes_ = 0;\n  }\n\n  /**\n   * @override\n   */\n  isInputValid() {\n    return this.state_ != Parser.State_.INVALID;\n  }\n\n  /**\n   * @override\n   */\n  getErrorMessage() {\n    return this.errorMessage_;\n  }\n\n  /**\n   * @override\n   * @return {boolean}\n   */\n  acceptsBinaryInput() {\n    return true;\n  }\n\n  /**\n   * Parse the new input.\n   *\n   * Note that there is no Parser state to indicate the end of a stream.\n   *\n   * @param {string|!ArrayBuffer|!Uint8Array|!Array<number>} input The input\n   *     data\n   * @throws {!Error} Throws an error message if the input is invalid.\n   * @return {?Array<string|!Object>} any parsed objects (atomic messages)\n   *    in an array, or null if more data needs be read to parse any new object.\n   * @override\n   */\n  parse(input) {\n    asserts.assert(\n        input instanceof Array || input instanceof ArrayBuffer ||\n        input instanceof Uint8Array);\n\n    var parser = this;\n    var inputBytes;\n    var pos = 0;\n\n    if (input instanceof Uint8Array || input instanceof Array) {\n      inputBytes = input;\n    } else {\n      inputBytes = new Uint8Array(input);\n    }\n\n    while (pos < inputBytes.length) {\n      switch (parser.state_) {\n        case Parser.State_.INVALID: {\n          parser.error_(inputBytes, pos, 'stream already broken');\n          break;\n        }\n        case Parser.State_.INIT: {\n          processFrameByte(inputBytes[pos]);\n          break;\n        }\n        case Parser.State_.LENGTH: {\n          processLengthByte(inputBytes[pos]);\n          break;\n        }\n        case Parser.State_.MESSAGE: {\n          processMessageByte(inputBytes[pos]);\n          break;\n        }\n        default: {\n          throw new Error('unexpected parser state: ' + parser.state_);\n        }\n      }\n\n      parser.streamPos_++;\n      pos++;\n    }\n\n    var msgs = parser.result_;\n    parser.result_ = [];\n    return msgs.length > 0 ? msgs : null;\n\n    /**\n     * @param {number} b A frame byte to process\n     */\n    function processFrameByte(b) {\n      if (b == FrameType.DATA) {\n        parser.frame_ = b;\n      } else if (b == FrameType.TRAILER) {\n        parser.frame_ = b;\n      } else {\n        parser.error_(inputBytes, pos, 'invalid frame byte');\n      }\n\n      parser.state_ = Parser.State_.LENGTH;\n      parser.length_ = 0;\n      parser.countLengthBytes_ = 0;\n    }\n\n    /**\n     * @param {number} b A length byte to process\n     */\n    function processLengthByte(b) {\n      parser.countLengthBytes_++;\n      parser.length_ = (parser.length_ << 8) + b;\n\n      if (parser.countLengthBytes_ == 4) {  // no more length byte\n        parser.state_ = Parser.State_.MESSAGE;\n        parser.countMessageBytes_ = 0;\n        if (typeof Uint8Array !== 'undefined') {\n          parser.messageBuffer_ = new Uint8Array(parser.length_);\n        } else {\n          parser.messageBuffer_ = new Array(parser.length_);\n        }\n\n        if (parser.length_ == 0) {  // empty message\n          finishMessage();\n        }\n      }\n    }\n\n    /**\n     * @param {number} b A message byte to process\n     */\n    function processMessageByte(b) {\n      parser.messageBuffer_[parser.countMessageBytes_++] = b;\n      if (parser.countMessageBytes_ == parser.length_) {\n        finishMessage();\n      }\n    }\n\n    /**\n     * Finishes up building the current message and resets parser state\n     */\n    function finishMessage() {\n      var message = {};\n      message[parser.frame_] = parser.messageBuffer_;\n      parser.result_.push(message);\n      parser.state_ = Parser.State_.INIT;\n    }\n  }\n}\n\n\nconst Parser = GrpcWebStreamParser;\n\n\n/**\n * The parser state.\n * @private @enum {number}\n */\nParser.State_ = {\n  INIT: 0,     // expecting the next frame byte\n  LENGTH: 1,   // expecting 4 bytes of length\n  MESSAGE: 2,  // expecting more message bytes\n  INVALID: 3\n};\n\n\n/**\n * Possible frame byte\n * @enum {number}\n */\nGrpcWebStreamParser.FrameType = {\n  DATA: 0x00,     // expecting a data frame\n  TRAILER: 0x80,  // expecting a trailer frame\n};\n\n\nvar FrameType = GrpcWebStreamParser.FrameType;\n\n\n\n/**\n * @param {!Uint8Array|!Array<number>} inputBytes The current input buffer\n * @param {number} pos The position in the current input that triggers the error\n * @param {string} errorMsg Additional error message\n * @throws {!Error} Throws an error indicating where the stream is broken\n * @private\n */\nParser.prototype.error_ = function(inputBytes, pos, errorMsg) {\n  this.state_ = Parser.State_.INVALID;\n  this.errorMessage_ = 'The stream is broken @' + this.streamPos_ + '/' + pos +\n      '. ' +\n      'Error: ' + errorMsg + '. ' +\n      'With input:\\n' + inputBytes;\n  throw new Error(this.errorMessage_);\n};\n\n\n\nexports = GrpcWebStreamParser;\n"
  },
  {
    "path": "javascript/net/grpc/web/grpcwebstreamparser_test.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\ngoog.module('grpc.web.GrpcWebStreamParserTest');\ngoog.setTestOnly('grpc.web.GrpcWebStreamParserTest');\n\nvar GrpcWebStreamParser = goog.require('grpc.web.GrpcWebStreamParser');\nvar testSuite = goog.require('goog.testing.testSuite');\ngoog.require('goog.testing.jsunit');\n\nvar parser;\nvar FrameType = GrpcWebStreamParser.FrameType;\n\n\ntestSuite({\n  setUp: function() {\n    parser = new GrpcWebStreamParser();\n  },\n\n  tearDown: function() {\n  },\n\n  testInvalidTagError: function() {\n    var arr = new Uint8Array([1, 0]);\n    assertThrows(function() { parser.parse(arr.buffer); });\n  },\n\n  testInvalidInputTypeInt: function() {\n    assertThrows(function() { parser.parse(0); });\n  },\n\n  testInvalidInputTypeObject: function() {\n    assertThrows(function() { parser.parse({}); });\n  },\n\n  testInvalidInputTypeString: function() {\n    assertThrows(function() { parser.parse(\"abc\"); });\n  },\n\n  testBasicMessage: function() {\n    var arr = new Uint8Array([0, 0, 0, 0, 2, 38, 39]);\n    var messages = parser.parse(arr.buffer);\n    assertEquals(1, messages.length);\n\n    var message = messages[0];\n    assertTrue(FrameType.DATA in message);\n    assertElementsEquals([38, 39], message[FrameType.DATA]);\n  },\n\n  testOneMessageOneTrailer: function() {\n    var arr = new Uint8Array([0, 0, 0, 0, 2, 38, 39, 128, 0, 0, 0, 2, 40, 41]);\n    var messages = parser.parse(arr.buffer);\n    assertEquals(2, messages.length);\n\n    var message = messages[0];\n    assertTrue(FrameType.DATA in message);\n    assertElementsEquals([38, 39], message[FrameType.DATA]);\n\n    var trailer = messages[1];\n    assertTrue(FrameType.TRAILER in trailer);\n    assertElementsEquals([40, 41], trailer[FrameType.TRAILER]);\n  },\n\n  testMultipleMessageOneTrailer: function() {\n    var arr = new Uint8Array([0, 0, 0, 0, 2, 38, 39, 0, 0, 0, 0, 3, 42, 43, 44,\n                              128, 0, 0, 0, 2, 40, 41]);\n    var messages = parser.parse(arr.buffer);\n    assertEquals(3, messages.length);\n\n    var message1 = messages[0];\n    assertTrue(FrameType.DATA in message1);\n    assertElementsEquals([38, 39], message1[FrameType.DATA]);\n\n    var message2 = messages[1];\n    assertTrue(FrameType.DATA in message2);\n    assertElementsEquals([42, 43, 44], message2[FrameType.DATA]);\n\n    var trailer = messages[2];\n    assertTrue(FrameType.TRAILER in trailer);\n    assertElementsEquals([40, 41], trailer[FrameType.TRAILER]);\n  },\n\n  testPartialMessage: function() {\n    var arr = new Uint8Array([0, 0, 0, 0, 2, 38]);\n    var messages = parser.parse(arr.buffer);\n    assertNull(messages);\n\n    arr = new Uint8Array([39]);\n    messages = parser.parse(arr.buffer);\n    assertEquals(1, messages.length);\n\n    var message = messages[0];\n    assertTrue(FrameType.DATA in message);\n    assertElementsEquals([38, 39], message[FrameType.DATA]);\n  },\n\n  testMultiplePartialMessages: function() {\n    var arr = new Uint8Array([0, 0, 0, 0, 2, 38]);\n    var messages = parser.parse(arr.buffer);\n    assertNull(messages);\n\n    arr = new Uint8Array([39, 128, 0, 0]);\n    messages = parser.parse(arr.buffer);\n    assertEquals(1, messages.length);\n\n    var message = messages[0];\n    assertTrue(FrameType.DATA in message);\n    assertElementsEquals([38, 39], message[FrameType.DATA]);\n\n    arr = new Uint8Array([0, 3, 40]);\n    messages = parser.parse(arr.buffer);\n    assertNull(messages);\n\n    arr = new Uint8Array([41, 42]);\n    messages = parser.parse(arr.buffer);\n    assertEquals(1, messages.length);\n\n    var trailer = messages[0];\n    assertTrue(FrameType.TRAILER in trailer);\n    assertElementsEquals([40, 41, 42], trailer[FrameType.TRAILER]);\n  },\n\n  testTrailerOnly: function() {\n    var arr = new Uint8Array([128, 0, 0, 0, 2, 40, 41]);\n    var messages = parser.parse(arr.buffer);\n    assertEquals(1, messages.length);\n\n    var trailer = messages[0];\n    assertTrue(FrameType.TRAILER in trailer);\n    assertElementsEquals([40, 41], trailer[FrameType.TRAILER]);\n  },\n\n  testEmptyMessage: function() {\n    var arr = new Uint8Array([0, 0, 0, 0, 0]);\n    var messages = parser.parse(arr.buffer);\n    assertEquals(1, messages.length);\n\n    var message = messages[0];\n    assertTrue(FrameType.DATA in message);\n    assertElementsEquals([], message[FrameType.DATA]);\n  },\n\n  testEmptyMessageWithTrailer: function() {\n    var arr = new Uint8Array([0, 0, 0, 0, 0, 128, 0, 0, 0, 1, 56]);\n    var messages = parser.parse(arr.buffer);\n    assertEquals(2, messages.length);\n\n    var message = messages[0];\n    assertTrue(FrameType.DATA in message);\n    assertElementsEquals([], message[FrameType.DATA]);\n\n    var trailer = messages[1];\n    assertTrue(FrameType.TRAILER in trailer);\n    assertElementsEquals([56], trailer[FrameType.TRAILER]);\n  },\n\n  testErrorAfterFirstMessage: function() {\n    var arr = new Uint8Array([0, 0, 0, 0, 2, 38, 39]);\n    var messages = parser.parse(arr.buffer);\n    assertEquals(1, messages.length);\n\n    var message = messages[0];\n    assertTrue(FrameType.DATA in message);\n    assertElementsEquals([38, 39], message[FrameType.DATA]);\n\n    arr = new Uint8Array([1, 0]);\n    assertThrows(function() { parser.parse(arr.buffer); });\n  },\n\n  testInvalidMessage: function() {\n    var arr = new Uint8Array([0, 0, 0, 0, 2, 38, 39, 40, 0, 0, 0, 0, 2, 41, 42]);\n    assertThrows(function() { parser.parse(arr.buffer); });\n  },\n\n  testEmptyArray: function() {\n    var arr = new Uint8Array([]);\n    var messages = parser.parse(arr.buffer);\n    assertNull(messages);\n  },\n\n  testMessageAfterEmptyArray: function() {\n    var arr = new Uint8Array([]);\n    var messages = parser.parse(arr.buffer);\n    assertNull(messages);\n\n    arr = new Uint8Array([]);\n    messages = parser.parse(arr.buffer);\n    assertNull(messages);\n\n    arr = new Uint8Array([0]);\n    messages = parser.parse(arr.buffer);\n    assertNull(messages);\n\n    arr = new Uint8Array([]);\n    messages = parser.parse(arr.buffer);\n    assertNull(messages);\n\n    arr = new Uint8Array([0, 0, 0]);\n    messages = parser.parse(arr.buffer);\n    assertNull(messages);\n\n    arr = new Uint8Array([]);\n    messages = parser.parse(arr.buffer);\n    assertNull(messages);\n\n    arr = new Uint8Array([2, 38, 39]);\n    messages = parser.parse(arr.buffer);\n    assertEquals(1, messages.length);\n\n    var message = messages[0];\n    assertTrue(FrameType.DATA in message);\n    assertElementsEquals([38, 39], message[FrameType.DATA]);\n  },\n\n});\n"
  },
  {
    "path": "javascript/net/grpc/web/interceptor.js",
    "content": "/**\n * @fileoverview grpc-web client interceptors.\n *\n * The type of interceptors is determined by the response type of the RPC call.\n * gRPC-Web has two generated clients for one service: \n * FooServiceClient and FooServicePromiseClient. The response type of\n * FooServiceClient is ClientReadableStream for BOTH unary calls and server\n * streaming calls, so StreamInterceptor is expected to be used for intercepting\n * FooServiceClient calls. The response type of PromiseClient is Promise, so use\n * UnaryInterceptor for PromiseClients.\n */\n\ngoog.module('grpc.web.Interceptor');\ngoog.module.declareLegacyNamespace();\n\n\nconst ClientReadableStream = goog.require('grpc.web.ClientReadableStream');\nconst Request = goog.require('grpc.web.Request');\nconst UnaryResponse = goog.require('grpc.web.UnaryResponse');\n\n/**\n * Interceptor for RPC calls with response type `UnaryResponse`.\n * An example implementation of UnaryInterceptor\n * <pre>\n * TestUnaryInterceptor.prototype.intercept = function(request, invoker) {\n *   const newRequest = ...\n *   return invoker(newRequest).then((response) => {\n *     // Do something with response.getMetadata\n       // Do something with response.getResponseMessage\n *     return response;\n *   });\n * };\n * </pre>\n * @interface\n */\nconst UnaryInterceptor = function() {};\n\n/**\n * @export\n * @abstract\n * @template REQUEST, RESPONSE\n * @param {!Request<REQUEST, RESPONSE>} request\n * @param {function(!Request<REQUEST,RESPONSE>):!Promise<!UnaryResponse<RESPONSE>>}\n *     invoker\n * @return {!Promise<!UnaryResponse<RESPONSE>>}\n */\nUnaryInterceptor.prototype.intercept = function(request, invoker) {};\n\n\n/**\n * Interceptor for RPC calls with response type `ClientReadableStream`.\n *\n * Two steps to create a stream interceptor:\n * <1>Create a new subclass of ClientReadableStream that wraps around the\n * original stream and overrides its methods. <2>Create a new subclass of\n * StreamInterceptor. While implementing the\n * StreamInterceptor.prototype.intercept method, return the wrapped\n * ClientReadableStream.\n * @interface\n */\nconst StreamInterceptor = function() {};\n\n/**\n * @export\n * @abstract\n * @template REQUEST, RESPONSE\n * @param {!Request<REQUEST, RESPONSE>} request\n * @param {function(!Request<REQUEST,RESPONSE>):!ClientReadableStream<RESPONSE>}\n *     invoker\n * @return {!ClientReadableStream<RESPONSE>}\n */\nStreamInterceptor.prototype.intercept = function(request, invoker) {};\n\n\nexports = {\n  UnaryInterceptor,\n  StreamInterceptor\n};\n"
  },
  {
    "path": "javascript/net/grpc/web/metadata.js",
    "content": "/**\n * @fileoverview grpc-web request/response metadata.\n *\n * Request and response headers will be included in the Metadata.\n */\n\ngoog.module('grpc.web.Metadata');\ngoog.module.declareLegacyNamespace();\n\n/**\n * @typedef {!Object<string,string>}\n */\nlet Metadata;\n\nexports = Metadata;\n"
  },
  {
    "path": "javascript/net/grpc/web/methoddescriptor.js",
    "content": "/**\n * @fileoverview Description of this file.\n *\n * A templated class that is used to address gRPC Web requests.\n */\n\ngoog.module('grpc.web.MethodDescriptor');\ngoog.module.declareLegacyNamespace();\n\nconst CallOptions = goog.require('grpc.web.CallOptions');\nconst Metadata = goog.requireType('grpc.web.Metadata');\nconst MethodDescriptorInterface = goog.requireType('grpc.web.MethodDescriptorInterface');\nconst MethodType = goog.requireType('grpc.web.MethodType');\nconst Request = goog.requireType('grpc.web.Request');\nconst RequestInternal = goog.require('grpc.web.RequestInternal');\nconst UnaryResponse = goog.requireType('grpc.web.UnaryResponse');\nconst UnaryResponseInternal = goog.require('grpc.web.UnaryResponseInternal');\nconst {Status} = goog.requireType('grpc.web.Status');\n\n/**\n * @final\n * @implements {MethodDescriptorInterface<REQUEST, RESPONSE>}\n * @template REQUEST, RESPONSE\n * @unrestricted\n */\nconst MethodDescriptor = class {\n  /**\n   * @param {string} name\n   * @param {?MethodType} methodType\n   * @param {function(new: REQUEST, ...)} requestType\n   * @param {function(new: RESPONSE, ...)} responseType\n   * @param {function(REQUEST): ?} requestSerializeFn\n   * @param {function(?): RESPONSE} responseDeserializeFn\n   */\n  constructor(\n      name, methodType, requestType, responseType, requestSerializeFn,\n      responseDeserializeFn) {\n    /** @const */\n    this.name = name;\n    /** @const */\n    this.methodType = methodType;\n    /** @const */\n    this.requestType = requestType;\n    /** @const */\n    this.responseType = responseType;\n    /** @const */\n    this.requestSerializeFn = requestSerializeFn;\n    /** @const */\n    this.responseDeserializeFn = responseDeserializeFn;\n  }\n\n  /**\n   * @override\n   * @param {REQUEST} requestMessage\n   * @param {!Metadata=} metadata\n   * @param {!CallOptions=} callOptions\n   * @return {!Request<REQUEST, RESPONSE>}\n   */\n  createRequest(\n      requestMessage, metadata = {}, callOptions = new CallOptions()) {\n    return new RequestInternal(requestMessage, this, metadata, callOptions);\n  }\n\n  /**\n   * @override\n   * @param {RESPONSE} responseMessage\n   * @param {!Metadata=} metadata\n   * @param {?Status=} status\n   * @return {!UnaryResponse<REQUEST, RESPONSE>}\n   */\n  createUnaryResponse(responseMessage, metadata = {}, status = null) {\n    return new UnaryResponseInternal(responseMessage, this, metadata, status);\n  }\n\n  /**\n   * @override\n   * @export\n   */\n  getName() {\n    return this.name;\n  }\n\n  /**\n   * @override\n   */\n  getMethodType() {\n    return this.methodType;\n  }\n\n  /**\n   * @override\n   * @return {function(new: RESPONSE, ...)}\n   */\n  getResponseMessageCtor() {\n    return this.responseType;\n  }\n\n  /**\n   * @override\n   * @return {function(new: REQUEST, ...)}\n   */\n  getRequestMessageCtor() {\n    return this.requestType;\n  }\n\n  /** @override */\n  getResponseDeserializeFn() {\n    return this.responseDeserializeFn;\n  }\n\n  /** @override */\n  getRequestSerializeFn() {\n    return this.requestSerializeFn;\n  }\n};\n\n\n\nexports = MethodDescriptor;\n"
  },
  {
    "path": "javascript/net/grpc/web/methoddescriptorinterface.js",
    "content": "/**\n * @fileoverview Description of this file.\n *\n * A templated class that is used to address gRPC Web requests.\n */\n\ngoog.module('grpc.web.MethodDescriptorInterface');\ngoog.module.declareLegacyNamespace();\n\nconst CallOptions = goog.requireType('grpc.web.CallOptions');\nconst Metadata = goog.requireType('grpc.web.Metadata');\nconst MethodType = goog.requireType('grpc.web.MethodType');\nconst Request = goog.requireType('grpc.web.Request');\nconst UnaryResponse = goog.requireType('grpc.web.UnaryResponse');\nconst {Status} = goog.requireType('grpc.web.Status');\n\n/**\n * @interface\n * @template REQUEST, RESPONSE\n */\nconst MethodDescriptorInterface = function() {};\n\n/**\n * @param {REQUEST} requestMessage\n * @param {!Metadata=} metadata\n * @param {!CallOptions=} callOptions\n * @return {!Request<REQUEST, RESPONSE>}\n */\nMethodDescriptorInterface.prototype.createRequest = function(\n    requestMessage, metadata, callOptions) {};\n\n\n/**\n * @param {RESPONSE} responseMessage\n * @param {!Metadata=} metadata\n * @param {?Status=} status\n * @return {!UnaryResponse<REQUEST, RESPONSE>}\n */\nMethodDescriptorInterface.prototype.createUnaryResponse = function(\n    responseMessage, metadata, status) {};\n\n/** @return {string} */\nMethodDescriptorInterface.prototype.getName = function() {};\n\n/** @return {?MethodType} */\nMethodDescriptorInterface.prototype.getMethodType = function() {};\n\n/** @return {function(new: RESPONSE, ?Array=)} */\nMethodDescriptorInterface.prototype.getResponseMessageCtor = function() {};\n\n/** @return {function(new: REQUEST, ?Array=)} */\nMethodDescriptorInterface.prototype.getRequestMessageCtor = function() {};\n\n/** @return {function(?): RESPONSE} */\nMethodDescriptorInterface.prototype.getResponseDeserializeFn = function() {};\n\n/** @return {function(REQUEST): ?} */\nMethodDescriptorInterface.prototype.getRequestSerializeFn = function() {};\n\nexports = MethodDescriptorInterface;\n"
  },
  {
    "path": "javascript/net/grpc/web/methodtype.js",
    "content": "/**\n * @fileoverview gRPC-Web method types.\n */\n\ngoog.module('grpc.web.MethodType');\n\ngoog.module.declareLegacyNamespace();\n\n/**\n * Available method types:\n * MethodType.UNARY: unary request and unary response.\n * MethodType.SERVER_STREAMING: unary request and streaming responses.\n * MethodType.BIDI_STREAMING: streaming requests and streaming responses.\n *\n * @enum {string}\n */\nconst MethodType = {\n  'UNARY': 'unary',\n  'SERVER_STREAMING': 'server_streaming',\n  // Bidi streaming is experimental. Do not use.\n  'BIDI_STREAMING': 'bidi_streaming',\n};\n\nexports = MethodType;\n"
  },
  {
    "path": "javascript/net/grpc/web/request.js",
    "content": "/**\n * @fileoverview  A templated class that is used to address an individual\n * gRPC-Web request instance.\n */\ngoog.module('grpc.web.Request');\ngoog.module.declareLegacyNamespace();\n\nconst CallOptions = goog.require('grpc.web.CallOptions');\nconst Metadata = goog.require('grpc.web.Metadata');\nconst MethodDescriptorInterface = goog.requireType('grpc.web.MethodDescriptorInterface');\n\n/**\n * @interface\n * @template REQUEST, RESPONSE\n */\nclass Request {\n  /**\n   * @export\n   * @return {REQUEST}\n   */\n  getRequestMessage() {}\n\n  /**\n   * @export\n   * @return {!MethodDescriptorInterface<REQUEST, RESPONSE>}\n   */\n  getMethodDescriptor() {}\n\n  /**\n   * @export\n   * @return {!Metadata}\n   */\n  getMetadata() {}\n\n  /**\n   * Client CallOptions. Note that CallOptions has not been implemented in\n   * grpc.web.AbstractClientbase yet, but will be used in\n   * grpc.web.GenericClient.\n   * @export\n   * @return {!CallOptions|undefined}\n   */\n  getCallOptions() {}\n\n  /**\n   * @param {string} key\n   * @param {string} value\n   * @return {!Request<REQUEST, RESPONSE>}\n   */\n  withMetadata(key, value) {}\n\n  /**\n   * @param {string} name\n   * @param {VALUE} value\n   * @template VALUE\n   * @return {!Request<REQUEST, RESPONSE>}\n   */\n  withGrpcCallOption(name, value) {}\n}\n\nexports = Request;\n"
  },
  {
    "path": "javascript/net/grpc/web/requestinternal.js",
    "content": "/**\n * @fileoverview Internal implementation of grpc.web.Request.\n */\ngoog.module('grpc.web.RequestInternal');\ngoog.module.declareLegacyNamespace();\n\nconst CallOptions = goog.require('grpc.web.CallOptions');\nconst Metadata = goog.require('grpc.web.Metadata');\nconst MethodDescriptor = goog.requireType('grpc.web.MethodDescriptor');\nconst Request = goog.require('grpc.web.Request');\n\n/**\n * @template REQUEST, RESPONSE\n * @implements {Request<REQUEST, RESPONSE>}\n * @final\n * @package\n */\nclass RequestInternal {\n  /**\n   * @param {REQUEST} requestMessage\n   * @param {!MethodDescriptor<REQUEST, RESPONSE>} methodDescriptor\n   * @param {!Metadata} metadata\n   * @param {!CallOptions} callOptions\n   */\n  constructor(requestMessage, methodDescriptor, metadata, callOptions) {\n    /**\n     * @const {REQUEST}\n     * @private\n     */\n    this.requestMessage_ = requestMessage;\n\n    /**\n     * @const {!MethodDescriptor<REQUEST, RESPONSE>}\n     * @private\n     */\n    this.methodDescriptor_ = methodDescriptor;\n\n    /** @const @private */\n    this.metadata_ = metadata;\n\n    /** @const @private */\n    this.callOptions_ = callOptions;\n  }\n\n  /**\n   * @override\n   * @return {REQUEST}\n   */\n  getRequestMessage() {\n    return this.requestMessage_;\n  }\n\n  /**\n   * @override\n   * @return {!MethodDescriptor<REQUEST, RESPONSE>}\n   */\n  getMethodDescriptor() {\n    return this.methodDescriptor_;\n  }\n\n  /**\n   * @override\n   * @return {!Metadata}\n   */\n  getMetadata() {\n    return this.metadata_;\n  }\n\n  /**\n   * @override\n   * @return {!CallOptions|undefined}\n   */\n  getCallOptions() {\n    return this.callOptions_;\n  }\n\n  /**\n   * @override\n   */\n  withMetadata(key, value) {\n    this.metadata_[key] = value;\n    return this;\n  }\n\n  /**\n   * @override\n   */\n  withGrpcCallOption(name, value) {\n    this.callOptions_.setOption(name, value);\n    return this;\n  }\n}\n\nexports = RequestInternal;\n"
  },
  {
    "path": "javascript/net/grpc/web/rpcerror.js",
    "content": "/**\n *\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n/**\n * @fileoverview gRPC-Web Error objects\n *\n * gRPC-Web Error objects\n *\n * @suppress {lintChecks} gRPC-Web is still using default goog.module exports\n * right now, and the output of grpc_generator.cc uses goog.provide.\n */\ngoog.module('grpc.web.RpcError');\n\nconst Metadata = goog.require('grpc.web.Metadata');\nconst StatusCode = goog.require('grpc.web.StatusCode');\n\n/**\n * gRPC-Web Error object, contains the {@link StatusCode}, a string message\n * and {@link Metadata} contained in the error response.\n */\nclass RpcError extends Error {\n  /**\n   * @param {!StatusCode} code\n   * @param {string} message\n   * @param {!Metadata=} metadata\n   */\n  constructor(code, message, metadata = {}) {\n    super(message);\n    /** @type {!StatusCode} */\n    this.code = code;\n    /** @type {!Metadata} */\n    this.metadata = metadata;\n  }\n\n  /** @override */\n  toString() {\n    const status = StatusCode.statusCodeName(this.code) || String(this.code);\n    let out = `RpcError(${status})`;\n    if (this.message) {\n      out += ': ' + this.message;\n    }\n    return out;\n  }\n}\n\n/** @override */\nRpcError.prototype.name = 'RpcError';\n\nexports = RpcError;\n"
  },
  {
    "path": "javascript/net/grpc/web/status.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n/**\n * @fileoverview gRPC Web Status codes and mapping.\n *\n * gRPC Web Status codes and mapping.\n *\n * @author stanleycheung@google.com (Stanley Cheung)\n */\ngoog.module('grpc.web.Status');\ngoog.module.declareLegacyNamespace();\n\n\n/** @record */\nfunction Status() {}\n\n/** @export {number} */\nStatus.prototype.code;\n\n/** @export {string} */\nStatus.prototype.details;\n\n/** @export {(!Object<string, string>|undefined)} */\nStatus.prototype.metadata;\n\nexports.Status = Status;\n"
  },
  {
    "path": "javascript/net/grpc/web/statuscode.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n/**\n * @fileoverview gRPC Web Status codes and mapping.\n *\n * gRPC Web Status codes and mapping.\n *\n * @author stanleycheung@google.com (Stanley Cheung)\n */\ngoog.module('grpc.web.StatusCode');\n\n/**\n * gRPC Status Codes\n * See:\n * https://github.com/grpc/grpc/blob/master/include/grpcpp/impl/codegen/status_code_enum.h\n * @enum {number}\n */\nconst StatusCode = {\n  // LINT.IfChange(status_codes)\n\n  // Not an error; returned on success.\n  'OK': 0,\n\n  // The operation was cancelled (typically by the caller).\n  'CANCELLED': 1,\n\n  // Unknown error. An example of where this error may be returned is if a\n  // Status value received from another address space belongs to an error-space\n  // that is not known in this address space. Also errors raised by APIs that\n  // do not return enough error information may be converted to this error.\n  'UNKNOWN': 2,\n\n  // Client specified an invalid argument. Note that this differs from\n  // FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are\n  // problematic regardless of the state of the system (e.g., a malformed file\n  // name).\n  'INVALID_ARGUMENT': 3,\n\n  // Deadline expired before operation could complete. For operations that\n  // change the state of the system, this error may be returned even if the\n  // operation has completed successfully. For example, a successful response\n  // from a server could have been delayed long enough for the deadline to\n  // expire.\n  'DEADLINE_EXCEEDED': 4,\n\n  // Some requested entity (e.g., file or directory) was not found.\n  'NOT_FOUND': 5,\n\n  // Some entity that we attempted to create (e.g., file or directory) already\n  // exists.\n  'ALREADY_EXISTS': 6,\n\n  // The caller does not have permission to execute the specified operation.\n  // PERMISSION_DENIED must not be used for rejections caused by exhausting\n  // some resource (use RESOURCE_EXHAUSTED instead for those errors).\n  // PERMISSION_DENIED must not be used if the caller can not be identified\n  // (use UNAUTHENTICATED instead for those errors).\n  'PERMISSION_DENIED': 7,\n\n  // The request does not have valid authentication credentials for the\n  // operation.\n  'UNAUTHENTICATED': 16,\n\n  // Some resource has been exhausted, perhaps a per-user quota, or perhaps the\n  // entire file system is out of space.\n  'RESOURCE_EXHAUSTED': 8,\n\n  // Operation was rejected because the system is not in a state required for\n  // the operation's execution. For example, directory to be deleted may be\n  // non-empty, an rmdir operation is applied to a non-directory, etc.\n  //\n  // A litmus test that may help a service implementor in deciding\n  // between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:\n  //  (a) Use UNAVAILABLE if the client can retry just the failing call.\n  //  (b) Use ABORTED if the client should retry at a higher-level\n  //      (e.g., restarting a read-modify-write sequence).\n  //  (c) Use FAILED_PRECONDITION if the client should not retry until\n  //      the system state has been explicitly fixed. E.g., if an \"rmdir\"\n  //      fails because the directory is non-empty, FAILED_PRECONDITION\n  //      should be returned since the client should not retry unless\n  //      they have first fixed up the directory by deleting files from it.\n  //  (d) Use FAILED_PRECONDITION if the client performs conditional\n  //      REST Get/Update/Delete on a resource and the resource on the\n  //      server does not match the condition. E.g., conflicting\n  //      read-modify-write on the same resource.\n  'FAILED_PRECONDITION': 9,\n\n  // The operation was aborted, typically due to a concurrency issue like\n  // sequencer check failures, transaction aborts, etc.\n  //\n  // See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,\n  // and UNAVAILABLE.\n  'ABORTED': 10,\n\n  // Operation was attempted past the valid range. E.g., seeking or reading\n  // past end of file.\n  //\n  // Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed\n  // if the system state changes. For example, a 32-bit file system will\n  // generate INVALID_ARGUMENT if asked to read at an offset that is not in the\n  // range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from\n  // an offset past the current file size.\n  //\n  // There is a fair bit of overlap between FAILED_PRECONDITION and\n  // OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific error)\n  // when it applies so that callers who are iterating through a space can\n  // easily look for an OUT_OF_RANGE error to detect when they are done.\n  'OUT_OF_RANGE': 11,\n\n  // Operation is not implemented or not supported/enabled in this service.\n  'UNIMPLEMENTED': 12,\n\n  // Internal errors. Means some invariants expected by underlying System has\n  // been broken. If you see one of these errors, Something is very broken.\n  'INTERNAL': 13,\n\n  // The service is currently unavailable. This is a most likely a transient\n  // condition and may be corrected by retrying with a backoff.\n  //\n  // See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,\n  // and UNAVAILABLE.\n  'UNAVAILABLE': 14,\n\n  // Unrecoverable data loss or corruption.\n  'DATA_LOSS': 15,\n\n  // LINT.ThenChange(:status_code_name)\n};\n\n/**\n * Convert HTTP Status code to gRPC Status code\n * @param {number} httpStatus HTTP Status Code\n * @return {!StatusCode} gRPC Status Code\n */\nStatusCode.fromHttpStatus = function(httpStatus) {\n  switch (httpStatus) {\n    case 200:\n      return StatusCode.OK;\n    case 400:\n      return StatusCode.INVALID_ARGUMENT;\n    case 401:\n      return StatusCode.UNAUTHENTICATED;\n    case 403:\n      return StatusCode.PERMISSION_DENIED;\n    case 404:\n      return StatusCode.NOT_FOUND;\n    case 409:\n      return StatusCode.ABORTED;\n    case 412:\n      return StatusCode.FAILED_PRECONDITION;\n    case 429:\n      return StatusCode.RESOURCE_EXHAUSTED;\n    case 499:\n      return StatusCode.CANCELLED;\n    case 500:\n      return StatusCode.UNKNOWN;\n    case 501:\n      return StatusCode.UNIMPLEMENTED;\n    case 503:\n      return StatusCode.UNAVAILABLE;\n    case 504:\n      return StatusCode.DEADLINE_EXCEEDED;\n    /* everything else is unknown */\n    default:\n      return StatusCode.UNKNOWN;\n  }\n};\n\n\n/**\n * Convert a {@link StatusCode} to an HTTP Status code\n * @param {!StatusCode} statusCode GRPC Status Code\n * @return {number} HTTP Status code\n */\nStatusCode.getHttpStatus = function(statusCode) {\n  switch (statusCode) {\n    case StatusCode.OK:\n      return 200;\n    case StatusCode.INVALID_ARGUMENT:\n      return 400;\n    case StatusCode.UNAUTHENTICATED:\n      return 401;\n    case StatusCode.PERMISSION_DENIED:\n      return 403;\n    case StatusCode.NOT_FOUND:\n      return 404;\n    case StatusCode.ABORTED:\n      return 409;\n    case StatusCode.FAILED_PRECONDITION:\n      return 412;\n    case StatusCode.RESOURCE_EXHAUSTED:\n      return 429;\n    case StatusCode.CANCELLED:\n      return 499;\n    case StatusCode.UNKNOWN:\n      return 500;\n    case StatusCode.UNIMPLEMENTED:\n      return 501;\n    case StatusCode.UNAVAILABLE:\n      return 503;\n    case StatusCode.DEADLINE_EXCEEDED:\n      return 504;\n    /* everything else is unknown */\n    default:\n      return 0;\n  }\n};\n\n/**\n * Returns the human readable name for a {@link StatusCode}. Useful for logging.\n * @param {!StatusCode} statusCode GRPC Status Code\n * @return {string} the human readable name for the status code\n */\nStatusCode.statusCodeName = function(statusCode) {\n  switch (statusCode) {\n      // LINT.IfChange(status_code_name)\n    case StatusCode.OK:\n      return 'OK';\n    case StatusCode.CANCELLED:\n      return 'CANCELLED';\n    case StatusCode.UNKNOWN:\n      return 'UNKNOWN';\n    case StatusCode.INVALID_ARGUMENT:\n      return 'INVALID_ARGUMENT';\n    case StatusCode.DEADLINE_EXCEEDED:\n      return 'DEADLINE_EXCEEDED';\n    case StatusCode.NOT_FOUND:\n      return 'NOT_FOUND';\n    case StatusCode.ALREADY_EXISTS:\n      return 'ALREADY_EXISTS';\n    case StatusCode.PERMISSION_DENIED:\n      return 'PERMISSION_DENIED';\n    case StatusCode.UNAUTHENTICATED:\n      return 'UNAUTHENTICATED';\n    case StatusCode.RESOURCE_EXHAUSTED:\n      return 'RESOURCE_EXHAUSTED';\n    case StatusCode.FAILED_PRECONDITION:\n      return 'FAILED_PRECONDITION';\n    case StatusCode.ABORTED:\n      return 'ABORTED';\n    case StatusCode.OUT_OF_RANGE:\n      return 'OUT_OF_RANGE';\n    case StatusCode.UNIMPLEMENTED:\n      return 'UNIMPLEMENTED';\n    case StatusCode.INTERNAL:\n      return 'INTERNAL';\n    case StatusCode.UNAVAILABLE:\n      return 'UNAVAILABLE';\n    case StatusCode.DATA_LOSS:\n      return 'DATA_LOSS';\n    default:\n      return '';\n    // LINT.ThenChange(:status_codes)\n  }\n};\n\nexports = StatusCode;\n"
  },
  {
    "path": "javascript/net/grpc/web/statuscode_test.js",
    "content": "goog.module('grpc.web.StatusCodeTest');\ngoog.setTestOnly('grpc.web.StatusCodeTest');\n\nconst StatusCode = goog.require('grpc.web.StatusCode');\nconst testSuite = goog.require('goog.testing.testSuite');\n\n\n/** @type {!Map<number, !StatusCode>} */\nconst statusMap = new Map([\n  [200, StatusCode.OK],\n  [400, StatusCode.INVALID_ARGUMENT],\n  [401, StatusCode.UNAUTHENTICATED],\n  [403, StatusCode.PERMISSION_DENIED],\n  [404, StatusCode.NOT_FOUND],\n  [409, StatusCode.ABORTED],\n  [412, StatusCode.FAILED_PRECONDITION],\n  [429, StatusCode.RESOURCE_EXHAUSTED],\n  [500, StatusCode.UNKNOWN],\n  [501, StatusCode.UNIMPLEMENTED],\n  [503, StatusCode.UNAVAILABLE],\n  [504, StatusCode.DEADLINE_EXCEEDED],\n]);\n\ntestSuite({\n  testFromHttpStatus() {\n    statusMap.forEach((statusCode, httpStatus) => {\n      assertEquals(StatusCode.fromHttpStatus(httpStatus), statusCode);\n    });\n  },\n\n  testGetHttpStatus() {\n    statusMap.forEach((statusCode, httpStatus) => {\n      assertEquals(StatusCode.getHttpStatus(statusCode), httpStatus);\n    });\n  },\n\n  testUnknown() {\n    assertEquals(StatusCode.getHttpStatus(StatusCode.UNKNOWN), 500);\n    assertEquals(StatusCode.fromHttpStatus(511), StatusCode.UNKNOWN);\n  }\n});"
  },
  {
    "path": "javascript/net/grpc/web/unaryresponse.js",
    "content": "/**\n * @fileoverview gRPC web client UnaryResponse returned by grpc unary calls.\n */\n\ngoog.module('grpc.web.UnaryResponse');\ngoog.module.declareLegacyNamespace();\n\nconst Metadata = goog.requireType('grpc.web.Metadata');\nconst MethodDescriptorInterface = goog.requireType('grpc.web.MethodDescriptorInterface');\nconst {Status} = goog.requireType('grpc.web.Status');\n\n/**\n * @interface\n * @template REQUEST, RESPONSE\n */\nclass UnaryResponse {\n  /**\n   * @export\n   * @return {RESPONSE}\n   */\n  getResponseMessage() {}\n\n  /**\n   * @export\n   * @return {!Metadata}\n   */\n  getMetadata() {}\n\n  /**\n   * @export\n   * @return {!MethodDescriptorInterface<REQUEST, RESPONSE>}\n   */\n  getMethodDescriptor() {}\n\n  /**\n   * gRPC status. Trailer metadata returned from a gRPC server is in\n   * status.metadata.\n   * @export\n   * @return {?Status}\n   */\n  getStatus() {}\n}\n\nexports = UnaryResponse;\n"
  },
  {
    "path": "javascript/net/grpc/web/unaryresponseinternal.js",
    "content": "/**\n * @fileoverview gRPC-Web UnaryResponse internal implementation.\n */\n\ngoog.module('grpc.web.UnaryResponseInternal');\ngoog.module.declareLegacyNamespace();\n\nconst Metadata = goog.requireType('grpc.web.Metadata');\nconst MethodDescriptor = goog.requireType('grpc.web.MethodDescriptor');\nconst UnaryResponse = goog.requireType('grpc.web.UnaryResponse');\nconst {Status} = goog.requireType('grpc.web.Status');\n\n/**\n * @template REQUEST, RESPONSE\n * @implements {UnaryResponse<REQUEST, RESPONSE>}\n * @final\n * @package\n */\nclass UnaryResponseInternal {\n  /**\n   * @param {RESPONSE} responseMessage\n   * @param {!MethodDescriptor<REQUEST, RESPONSE>} methodDescriptor\n   * @param {!Metadata=} metadata\n   * @param {?Status=} status\n   */\n  constructor(responseMessage, methodDescriptor, metadata = {}, status = null) {\n    /**\n     * @const {RESPONSE}\n     * @private\n     */\n    this.responseMessage_ = responseMessage;\n\n    /**\n     * @const {!Metadata}\n     * @private\n     */\n    this.metadata_ = metadata;\n\n    /**\n     * @const {!MethodDescriptor<REQUEST, RESPONSE>}\n     * @private\n     */\n    this.methodDescriptor_ = methodDescriptor;\n\n    /**\n     * @const {?Status}\n     * @private\n     */\n    this.status_ = status;\n  }\n\n  /** @override */\n  getResponseMessage() {\n    return this.responseMessage_;\n  }\n\n  /** @override */\n  getMetadata() {\n    return this.metadata_;\n  }\n\n  /** @override */\n  getMethodDescriptor() {\n    return this.methodDescriptor_;\n  }\n\n  /** @override */\n  getStatus() {\n    return this.status_;\n  }\n}\n\nexports = UnaryResponseInternal;\n"
  },
  {
    "path": "kokoro/interop.cfg",
    "content": "build_file: \"grpc-web/scripts/run_interop_tests.sh\"\n"
  },
  {
    "path": "kokoro/master.cfg",
    "content": "build_file: \"grpc-web/scripts/kokoro.sh\"\n"
  },
  {
    "path": "kokoro/presubmit.cfg",
    "content": "build_file: \"grpc-web/scripts/run_basic_tests.sh\"\n"
  },
  {
    "path": "net/grpc/gateway/docker/binary_client/Dockerfile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM grpcweb/prereqs\n\nWORKDIR /github/grpc-web/net/grpc/gateway/examples/echo\n\nRUN protoc -I=. echo.proto \\\n--js_out=import_style=commonjs:./commonjs-example \\\n--grpc-web_out=import_style=commonjs,mode=grpcweb:./commonjs-example\n\nWORKDIR /github/grpc-web/net/grpc/gateway/examples/echo/commonjs-example\n\nRUN npm install && \\\n  npm link grpc-web && \\\n  npx webpack && \\\n  cp echotest.html /var/www/html && \\\n  cp dist/main.js /var/www/html/dist\n\nWORKDIR /var/www/html\n\nEXPOSE 8081\nCMD [\"python\", \"-m\", \"SimpleHTTPServer\", \"8081\"]\n"
  },
  {
    "path": "net/grpc/gateway/docker/closure_client/Dockerfile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM grpcweb/prereqs\n\nWORKDIR /github/grpc-web/net/grpc/gateway/examples/echo\n\nRUN npm install\n\nRUN make client && make install\n\nWORKDIR /var/www/html\n\nEXPOSE 8081\nCMD [\"python\", \"-m\", \"SimpleHTTPServer\", \"8081\"]\n"
  },
  {
    "path": "net/grpc/gateway/docker/commonjs_client/Dockerfile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM grpcweb/prereqs\n\nWORKDIR /github/grpc-web/net/grpc/gateway/examples/echo\n\nRUN protoc -I=. echo.proto \\\n--js_out=import_style=commonjs:./commonjs-example \\\n--grpc-web_out=import_style=commonjs,mode=grpcwebtext:./commonjs-example\n\nWORKDIR /github/grpc-web/net/grpc/gateway/examples/echo/commonjs-example\n\nRUN npm install && \\\n  npm link grpc-web && \\\n  npx webpack && \\\n  cp echotest.html /var/www/html && \\\n  cp dist/main.js /var/www/html/dist\n\nWORKDIR /var/www/html\n\nEXPOSE 8081\nCMD [\"python\", \"-m\", \"SimpleHTTPServer\", \"8081\"]\n"
  },
  {
    "path": "net/grpc/gateway/docker/echo_server/Dockerfile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM grpcweb/prereqs\n\nWORKDIR /github/grpc-web\n\nRUN bazel build net/grpc/gateway/examples/echo:server\n\nWORKDIR /github/grpc-web/bazel-bin/net/grpc/gateway/examples/echo\n\nEXPOSE 9090\nCMD [\"./server\"]\n"
  },
  {
    "path": "net/grpc/gateway/docker/envoy/Dockerfile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM envoyproxy/envoy:v1.22.0\n\nCOPY net/grpc/gateway/examples/echo/envoy.yaml /etc/envoy/envoy.yaml\n\nENTRYPOINT [ \"/usr/local/bin/envoy\" ]\nCMD [ \"-c /etc/envoy/envoy.yaml\", \"-l trace\", \"--log-path /tmp/envoy_info.log\" ]\n"
  },
  {
    "path": "net/grpc/gateway/docker/grpcwebproxy/Dockerfile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM golang:1.16-alpine3.13\n\nRUN apk add --no-cache curl git ca-certificates && \\\n  rm -rf /var/lib/apt/lists/*\n\nARG VERSION=0.14.0\n\nWORKDIR /tmp\n\nRUN curl -sS https://raw.githubusercontent.com/golang/dep/master/install.sh | sh\nRUN wget https://github.com/improbable-eng/grpc-web/archive/v$VERSION.tar.gz\n\nWORKDIR /go/src/github.com/improbable-eng/\n\nRUN tar -zxf /tmp/v$VERSION.tar.gz -C .\nRUN mv grpc-web-$VERSION grpc-web\n\nWORKDIR /go/src/github.com/improbable-eng/grpc-web\n\nRUN dep ensure && \\\n  go env -w GO111MODULE=auto && \\\n  go install ./go/grpcwebproxy\n\nADD ./etc/localhost.crt /etc\nADD ./etc/localhost.key /etc\n\nENTRYPOINT [ \"/bin/sh\", \"-c\", \"exec /go/bin/grpcwebproxy \\\n  --backend_addr=node-server:9090 \\\n  --run_tls_server=false \\\n  --allow_all_origins \" ]\n"
  },
  {
    "path": "net/grpc/gateway/docker/interop_client/Dockerfile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM grpcweb/prereqs\n\nWORKDIR /github/grpc-web/test/interop\n\nCOPY ./test/interop .\n\nRUN protoc -I=../.. src/proto/grpc/testing/test.proto \\\nsrc/proto/grpc/testing/empty.proto src/proto/grpc/testing/messages.proto \\\n--js_out=import_style=commonjs:. \\\n--grpc-web_out=import_style=commonjs,mode=grpcwebtext:.\n\nRUN npm install && \\\n  npm link grpc-web && \\\n  npx webpack && \\\n  cp index.html /var/www/html && \\\n  cp dist/main.js /var/www/html/dist\n\nWORKDIR /var/www/html\n\nEXPOSE 8081\nCMD [\"python\", \"-m\", \"SimpleHTTPServer\", \"8081\"]\n"
  },
  {
    "path": "net/grpc/gateway/docker/node_interop_server/Dockerfile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM node:20.0.0-bullseye\n\nWORKDIR /github/grpc-node\n\nRUN git clone https://github.com/grpc/grpc-node . && \\\n  git submodule --quiet update --init --recursive\n\nRUN cd packages/grpc-native-core && \\\n  npm install --build-from-source --unsafe-perm && \\\n  npm link\n\nRUN cd packages/proto-loader && \\\n  npm install @types/mocha@7.0.2&& \\\n  npm install --unsafe-perm\n\nWORKDIR /github/grpc-node/test\n\nRUN npm install node-pre-gyp && \\\n  npm install && \\\n  npm link grpc\n\nEXPOSE 7074\nCMD [\"node\", \"--require\", \"./fixtures/native_native\", \"./interop/interop_server.js\", \"--port=7074\"]\n"
  },
  {
    "path": "net/grpc/gateway/docker/node_server/Dockerfile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM grpcweb/prereqs\n\nWORKDIR /github/grpc-web/net/grpc/gateway/examples/echo/node-server\n\nRUN npm install\n\nEXPOSE 9090\nCMD [\"node\", \"server.js\"]\n"
  },
  {
    "path": "net/grpc/gateway/docker/prereqs/Dockerfile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\n# Using multi-stage buid (See: https://docs.docker.com/develop/develop-images/multistage-build/)\n\n######################################\n# Stage 1: Fetch binaries\n######################################\n# node:... Docker image is based on buildpack-deps:bullseye (11)\nFROM buildpack-deps:bullseye AS prepare\n\nARG BUILDIFIER_VERSION=1.0.0\nARG PROTOBUF_VERSION=3.19.4\n\nRUN apt-get -qq update && apt-get -qq install -y curl unzip\n\nWORKDIR /tmp\n\nRUN curl -sSL https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOBUF_VERSION/\\\nprotoc-$PROTOBUF_VERSION-linux-x86_64.zip -o protoc.zip && \\\n  unzip -qq protoc.zip && \\\n  cp ./bin/protoc /usr/local/bin/protoc\n\nRUN wget -nv -O buildifier \\\n  https://github.com/bazelbuild/buildtools/releases/download/$BUILDIFIER_VERSION/buildifier && \\\n  chmod +x ./buildifier && \\\n  cp ./buildifier /usr/local/bin/buildifier\n\n# Download third_party modules to be used for the next stage\nWORKDIR /github/grpc-web\n\nRUN git clone https://github.com/grpc/grpc-web .\nCOPY ./scripts/init_submodules.sh ./scripts/\nRUN ./scripts/init_submodules.sh\n\n######################################\n# Stage 2: Copy source files and build\n######################################\nFROM node:20.0.0-bullseye AS copy-and-build\n\nARG MAKEFLAGS=-j8\nARG BAZEL_VERSION=7.3.0\n\nRUN apt-get -qq update && apt-get -qq install -y python\n\nRUN mkdir -p /var/www/html/dist\nRUN echo \"\\nloglevel=error\\n\" >> $HOME/.npmrc\n\nCOPY --from=prepare /usr/local/bin/protoc /usr/local/bin/\nCOPY --from=prepare /usr/local/bin/buildifier /usr/local/bin/\nCOPY --from=prepare /github/grpc-web/third_party /github/grpc-web/third_party\n\nRUN wget -nv -O bazel-installer.sh \\\n  https://github.com/bazelbuild/bazel/releases/download/$BAZEL_VERSION/\\\nbazel-$BAZEL_VERSION-installer-linux-x86_64.sh && \\\n  chmod +x ./bazel-installer.sh && \\\n  ./bazel-installer.sh && \\\n  rm ./bazel-installer.sh\n\nWORKDIR /github/grpc-web\n\n# Copy only files necessary to build the protoc-gen-grpc-web first as an optimization because they\n# are rarely updated compared with the javascript files.\nCOPY ./MODULE.bazel ./MODULE.bazel\nCOPY ./MODULE.bazel.lock ./MODULE.bazel.lock\nCOPY ./.bazelrc ./.bazelrc\nCOPY ./javascript/net/grpc/web/generator javascript/net/grpc/web/generator\n\n# Pre-build the protobuf compiler lib so the following plugin build can reuse Bazel cache.\nRUN bazel build \"@com_google_protobuf//:protoc_lib\"\n\nRUN bazel build javascript/net/grpc/web/generator:protoc-gen-grpc-web && \\\n  cp $(bazel info bazel-genfiles)/javascript/net/grpc/web/generator/protoc-gen-grpc-web \\\n  /usr/local/bin/protoc-gen-grpc-web\n\nCOPY ./javascript ./javascript\nCOPY ./packages ./packages\n\nRUN cd ./packages/grpc-web && \\\n  npm install && \\\n  npm run build && \\\n  npm link\n\nCOPY ./Makefile ./Makefile\nCOPY ./net ./net\nCOPY ./scripts ./scripts\nCOPY ./src ./src\nCOPY ./test ./test\n\nRUN /usr/local/bin/buildifier \\\n  --mode=check --lint=warn --warnings=all -r ./MODULE.bazel javascript net\n"
  },
  {
    "path": "net/grpc/gateway/docker/ts_client/Dockerfile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nFROM grpcweb/prereqs\n\nWORKDIR /github/grpc-web\n\n# Bring in current workspace\nCOPY ./net/grpc/gateway/examples/echo ./net/grpc/gateway/examples/echo\n\nWORKDIR /github/grpc-web/net/grpc/gateway/examples/echo\n\nRUN protoc -I=. echo.proto \\\n--js_out=import_style=commonjs:./ts-example \\\n--grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:./ts-example\n\nWORKDIR /github/grpc-web/net/grpc/gateway/examples/echo/ts-example\n\nRUN npm install && \\\n  npm link grpc-web && \\\n  npx tsc && \\\n  # Since typescript@4.5.2, tsc has apparently stopped moving dependent js files into dist/ dir, so\n  # we'll move them manually.\n  mv *_pb.js dist/ && \\\n  npx webpack && \\\n  cp echotest.html /var/www/html && \\\n  cp dist/main.js /var/www/html/dist\n\nWORKDIR /var/www/html\n\nEXPOSE 8081\nCMD [\"python\", \"-m\", \"SimpleHTTPServer\", \"8081\"]\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/.gitignore",
    "content": "/package-lock.json\n/node_modules\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/BUILD.bazel",
    "content": "load(\"@com_github_grpc_grpc//bazel:cc_grpc_library.bzl\", \"cc_grpc_library\")\nload(\"@rules_cc//cc:defs.bzl\", \"cc_binary\", \"cc_proto_library\")\nload(\"@rules_proto//proto:defs.bzl\", \"proto_library\")\n\nproto_library(\n    name = \"echo_proto\",\n    srcs = [\n        \"echo.proto\",\n    ],\n)\n\n# Server\n\ncc_proto_library(\n    name = \"echo_cc_proto\",\n    deps = [\n        \":echo_proto\",\n    ],\n)\n\ncc_grpc_library(\n    name = \"echo_cc_grpc\",\n    srcs = [\n        \":echo_proto\",\n    ],\n    grpc_only = True,\n    deps = [\n        \":echo_cc_proto\",\n    ],\n)\n\ncc_binary(\n    name = \"server\",\n    srcs = [\n        \"echo_server.cc\",\n        \"echo_service_impl.cc\",\n        \"echo_service_impl.h\",\n    ],\n    deps = [\n        \":echo_cc_grpc\",\n        \":echo_cc_proto\",\n        \"@com_github_grpc_grpc//:grpc++\",\n    ],\n)\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/Makefile",
    "content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nROOT_DIR = ../../../../..\nNPM_DIR = ./node_modules\nPROTOC = protoc\nPROTOS_PATH = ../..\nHTML_DIR = /var/www/html\nJS_IMPORT_STYLE = import_style=closure,binary\nJS_PATH = javascript/net/grpc/web\nOUT_DIR = ./out\nPROTOBUF_PATH = third_party/protobuf\nGRPC_WEB_PLUGIN_PATH = /usr/local/bin/protoc-gen-grpc-web\n\nall: client\n\nclient: proto-js compiled-js\n\ncompiled-js:\n\t./node_modules/.bin/google-closure-compiler \\\n  --js=*.js \\\n  --js=$(OUT_DIR)/*.js \\\n  --js=$(ROOT_DIR)/javascript \\\n  --js=$(ROOT_DIR)/$(PROTOBUF_PATH)/js \\\n  --js='!$(ROOT_DIR)/$(PROTOBUF_PATH)/js/**/*_test.js' \\\n  --js=$(NPM_DIR)/google-closure-library \\\n  --entry_point=goog:proto.grpc.gateway.testing.EchoServiceClient \\\n  --dependency_mode=PRUNE \\\n  --js_output_file compiled.js\n\nproto-js:\n\tmkdir -p $(OUT_DIR)\n\t$(PROTOC) -I=$(ROOT_DIR)/$(PROTOBUF_PATH)/src/google/protobuf \\\n  --js_out=$(JS_IMPORT_STYLE):$(OUT_DIR) \\\n  $(ROOT_DIR)/$(PROTOBUF_PATH)/src/google/protobuf/any.proto\n\t$(PROTOC) -I=. --js_out=$(JS_IMPORT_STYLE):$(OUT_DIR) ./echo.proto\n\t$(PROTOC) -I=. --plugin=protoc-gen-grpc-web=$(GRPC_WEB_PLUGIN_PATH) \\\n  --grpc-web_out=import_style=closure,mode=grpcwebtext:. ./echo.proto\n\ninstall:\n\tmkdir -p $(HTML_DIR)\n\tcp ./echotest.html $(HTML_DIR)\n\tcp ./echoapp.js $(HTML_DIR)\n\tcp ./compiled.js $(HTML_DIR)/echo_js_bin_dev.js\n\nclean:\n\trm -f compiled.js\n\trm -f *_pb.js\n\trm -rf $(OUT_DIR)\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/README.md",
    "content": "## Build and Run an Echo example\n\nThis page will show you how to quickly build and run an end-to-end Echo\nexample. The example has 3 key components:\n\n - Front-end JS client\n - Envoy proxy\n - gRPC backend server (written in Node)\n\n\nFrom the repo root directory:\n\n## Build pre-requisites\n\nThis step downloads the necessary pre-requisites, and serves as the base docker\nimage for the subsequent docker images.\n\n```sh\n$ docker build -t grpcweb/prereqs \\\n  -f net/grpc/gateway/docker/prereqs/Dockerfile .\n```\n\n## Run the gRPC Backend server\n\nThis compiles the gRPC backend server, written in Node, and listens on port\n9090.\n\n```sh\n$ docker build -t grpcweb/node-server \\\n  -f net/grpc/gateway/docker/node_server/Dockerfile .\n$ docker run -d -p 9090:9090 --name node-server grpcweb/node-server\n```\n\n## Run the Envoy proxy\n\nThis step runs the Envoy proxy, and listens on port 8080. Any gRPC-Web browser\nrequests will be forwarded to port 9090.\n\n```sh\n$ docker build -t grpcweb/envoy \\\n  -f net/grpc/gateway/docker/envoy/Dockerfile .\n$ docker run -d -p 8080:8080 --link node-server:node-server grpcweb/envoy\n```\n\n## Serve static JS/HTML contents\n\nThis steps compiles the front-end gRPC-Web client into a static .JS file, and\nwe use a simple server to serve up the JS/HTML static contents.\n\n```sh\n$ docker build -t grpcweb/commonjs-client  \\\n  -f net/grpc/gateway/docker/commonjs_client/Dockerfile .\n$ docker run -d -p 8081:8081 grpcweb/commonjs-client\n```\n\n## Run the example from your browser\n\nFinally, open a browser tab, and inspect\n\n```\nhttp://localhost:8081/echotest.html\n```\n\n## What's next?\n\nFor more details about how you can run your own gRPC service and access it\nfrom the browser, please see this [tutorial](tutorial.md)\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/commonjs-example/.gitignore",
    "content": "node_modules\npackage-lock.json\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/commonjs-example/client.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nconst {EchoRequest,\n       ServerStreamingEchoRequest} = require('./echo_pb.js');\nconst {EchoServiceClient} = require('./echo_grpc_web_pb.js');\nconst {EchoApp} = require('../echoapp.js');\nconst grpc = {};\ngrpc.web = require('grpc-web');\n\n/** Sample interceptor implementation */\nconst StreamResponseInterceptor = function() {};\n\n/**\n * @template REQUEST, RESPONSE\n * @param {!Request<REQUEST, RESPONSE>} request\n * @param {function(!Request<REQUEST,RESPONSE>):!ClientReadableStream<RESPONSE>}\n *     invoker\n * @return {!ClientReadableStream<RESPONSE>}\n */\nStreamResponseInterceptor.prototype.intercept = function(request, invoker) {\n  const InterceptedStream = function(stream) {\n    this.stream = stream;\n  };\n  InterceptedStream.prototype.on = function(eventType, callback) {\n    if (eventType == 'data') {\n      const newCallback = (response) => {\n        response.setMessage('[Intcpt Resp1]'+response.getMessage());\n        callback(response);\n      };\n      this.stream.on(eventType, newCallback);\n    } else {\n      this.stream.on(eventType, callback);\n    }\n    return this;\n  };\n  var reqMsg = request.getRequestMessage();\n  reqMsg.setMessage('[Intcpt Req1]'+reqMsg.getMessage());\n  return new InterceptedStream(invoker(request));\n};\n\nvar opts = {'streamInterceptors' : [new StreamResponseInterceptor()]};\nvar echoService = new EchoServiceClient('http://'+window.location.hostname+':8080', null,\n                                        null);\n//                                      opts);\n\nvar echoApp = new EchoApp(\n  echoService,\n  {\n    EchoRequest: EchoRequest,\n    ServerStreamingEchoRequest: ServerStreamingEchoRequest\n  }\n);\n\nechoApp.load();\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/commonjs-example/echotest.html",
    "content": "<!-- Copyright 2018 Google LLC  -->\n\n<!-- Licensed under the Apache License, Version 2.0 (the \"License\");  -->\n<!-- you may not use this file except in compliance with the License.  -->\n<!-- You may obtain a copy of the License at  -->\n\n<!--     https://www.apache.org/licenses/LICENSE-2.0  -->\n\n<!-- Unless required by applicable law or agreed to in writing, software  -->\n<!-- distributed under the License is distributed on an \"AS IS\" BASIS,  -->\n<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  -->\n<!-- See the License for the specific language governing permissions and  -->\n<!-- limitations under the License.  -->\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>Echo Example</title>\n<link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\">\n<script src=\"//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>\n<script>\n  // Load the local /dist/main.js and use a random query parameter to disable caching.\n  const script = document.createElement('script');\n  script.src = `./dist/main.js?v=${Date.now()}`;\n  document.head.appendChild(script);\n</script>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"row\" id=\"first\">\n      <div class=\"form-group\">\n        <div class=\"input-group\">\n          <input type=\"text\" class=\"form-control\" id=\"msg\">\n          <span class=\"input-group-btn\">\n            <button class=\"btn btn-primary\" type=\"button\" id=\"send\">Send\n            </button>\n          </span>\n        </div>\n        <p class=\"help-block\">Example: \"Hello\", \"4 Hello\", \"err Hello\"</p>\n      </div>\n    </div>\n  </div>\n</body>\n</html>\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/commonjs-example/package.json",
    "content": "{\n  \"name\": \"grpc-web-commonjs-example\",\n  \"version\": \"0.1.0\",\n  \"description\": \"gRPC-Web CommonJS client example\",\n  \"license\": \"Apache-2.0\",\n  \"dependencies\": {\n    \"google-protobuf\": \"~3.21.4\",\n    \"grpc-web\": \"~2.0.2\"\n  },\n  \"devDependencies\": {\n    \"webpack\": \"5.101.3\",\n    \"webpack-cli\": \"~5.1.1\"\n  }\n}\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/commonjs-example/webpack.config.js",
    "content": "module.exports = {\n  mode: \"production\",\n  entry: \"./client.js\",\n};\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/echo.proto",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     https://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage grpc.gateway.testing;\n\nmessage Empty {}\n\nmessage EchoRequest {\n  string message = 1;\n}\n\nmessage EchoResponse {\n  string message = 1;\n  int32 message_count = 2;\n}\n\n// Request type for server side streaming echo.\nmessage ServerStreamingEchoRequest {\n  // Message string for server streaming request.\n  string message = 1;\n\n  // The total number of messages to be generated before the server\n  // closes the stream; default is 10.\n  int32 message_count = 2;\n\n  // The interval (ms) between two server messages. The server implementation\n  // may enforce some minimum interval (e.g. 100ms) to avoid message overflow.\n  int32 message_interval = 3;\n}\n\n// Response type for server streaming response.\nmessage ServerStreamingEchoResponse {\n  // Response message.\n  string message = 1;\n}\n\n// Request type for client side streaming echo.\nmessage ClientStreamingEchoRequest {\n  // A special value \"\" indicates that there's no further messages.\n  string message = 1;\n}\n\n// Response type for client side streaming echo.\nmessage ClientStreamingEchoResponse {\n  // Total number of client messages that have been received.\n  int32 message_count = 1;\n}\n\n// A simple echo service.\nservice EchoService {\n  // One request followed by one response\n  // The server returns the client message as-is.\n  rpc Echo(EchoRequest) returns (EchoResponse);\n\n  // Sends back abort status.\n  rpc EchoAbort(EchoRequest) returns (EchoResponse) {}\n\n  // One empty request, ZERO processing, followed by one empty response\n  // (minimum effort to do message serialization).\n  rpc NoOp(Empty) returns (Empty);\n\n  // One request followed by a sequence of responses (streamed download).\n  // The server will return the same client message repeatedly.\n  rpc ServerStreamingEcho(ServerStreamingEchoRequest)\n      returns (stream ServerStreamingEchoResponse);\n\n  // One request followed by a sequence of responses (streamed download).\n  // The server abort directly.\n  rpc ServerStreamingEchoAbort(ServerStreamingEchoRequest)\n      returns (stream ServerStreamingEchoResponse) {}\n\n  // A sequence of requests followed by one response (streamed upload).\n  // The server returns the total number of messages as the result.\n  // Notice: Client side streaming and Bidi streaming are not supported at the moment.\n  rpc ClientStreamingEcho(stream ClientStreamingEchoRequest)\n      returns (ClientStreamingEchoResponse);\n\n  // A sequence of requests with each message echoed by the server immediately.\n  // The server returns the same client messages in order.\n  // E.g. this is how the speech API works.\n  // Notice: Client side streaming and Bidi streaming are not supported at the moment.\n  rpc FullDuplexEcho(stream EchoRequest) returns (stream EchoResponse); \n\n  // A sequence of requests followed by a sequence of responses.\n  // The server buffers all the client messages and then returns the same\n  // client messages one by one after the client half-closes the stream.\n  // This is how an image recognition API may work.\n  // Notice: Client side streaming and Bidi streaming are not supported at the moment.\n  rpc HalfDuplexEcho(stream EchoRequest) returns (stream EchoResponse);\n}\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/echo_chat.js",
    "content": "// TODO: Implement simple chat client using ClosureJS (similar to echoapp.js).\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/echo_server.cc",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#include <grpcpp/grpcpp.h>\n#include <unistd.h>\n#include <string>\n\n#include \"net/grpc/gateway/examples/echo/echo.grpc.pb.h\"\n#include \"net/grpc/gateway/examples/echo/echo_service_impl.h\"\n\nusing grpc::Server;\nusing grpc::ServerBuilder;\n\nvoid RunServer() {\n  std::string server_address(\"0.0.0.0:9090\");\n  EchoServiceImpl service;\n  ServerBuilder builder;\n  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());\n  builder.RegisterService(&service);\n  std::unique_ptr<Server> server(builder.BuildAndStart());\n  server->Wait();\n}\n\nint main(int argc, char** argv) {\n  RunServer();\n\n  return 0;\n}\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/echo_service_impl.cc",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#include \"net/grpc/gateway/examples/echo/echo_service_impl.h\"\n\n#include <grpcpp/grpcpp.h>\n#include <unistd.h>\n#include <string>\n\n#include \"net/grpc/gateway/examples/echo/echo.grpc.pb.h\"\n\nusing grpc::ServerContext;\nusing grpc::ServerWriter;\nusing grpc::Status;\nusing grpc::gateway::testing::EchoRequest;\nusing grpc::gateway::testing::EchoResponse;\nusing grpc::gateway::testing::EchoService;\nusing grpc::gateway::testing::Empty;\nusing grpc::gateway::testing::ServerStreamingEchoRequest;\nusing grpc::gateway::testing::ServerStreamingEchoResponse;\n\n\nEchoServiceImpl::EchoServiceImpl() {}\nEchoServiceImpl::~EchoServiceImpl() {}\n\nvoid EchoServiceImpl::CopyClientMetadataToResponse(ServerContext* context) {\n  for (auto& client_metadata : context->client_metadata()) {\n    context->AddInitialMetadata(std::string(client_metadata.first.data(),\n                                            client_metadata.first.length()),\n                                std::string(client_metadata.second.data(),\n                                            client_metadata.second.length()));\n    context->AddTrailingMetadata(\n        std::string(client_metadata.first.data(),\n                    client_metadata.first.length()),\n        std::string(client_metadata.second.data(),\n                    client_metadata.second.length()));\n  }\n}\n\nStatus EchoServiceImpl::Echo(ServerContext* context, const EchoRequest* request,\n                             EchoResponse* response) {\n  CopyClientMetadataToResponse(context);\n  response->set_message(request->message());\n  return Status::OK;\n}\n\nStatus EchoServiceImpl::EchoAbort(ServerContext* context,\n                                  const EchoRequest* request,\n                                  EchoResponse* response) {\n  CopyClientMetadataToResponse(context);\n  response->set_message(request->message());\n  return Status(grpc::StatusCode::ABORTED,\n                \"Aborted from server side.\");\n}\n\nStatus EchoServiceImpl::NoOp(ServerContext* context, const Empty* request,\n                             Empty* response) {\n  CopyClientMetadataToResponse(context);\n  return Status::OK;\n}\n\nStatus EchoServiceImpl::ServerStreamingEcho(\n    ServerContext* context, const ServerStreamingEchoRequest* request,\n    ServerWriter<ServerStreamingEchoResponse>* writer) {\n  CopyClientMetadataToResponse(context);\n  for (int i = 0; i < request->message_count(); i++) {\n    if (context->IsCancelled()) {\n      return Status::CANCELLED;\n    }\n    ServerStreamingEchoResponse response;\n    response.set_message(request->message());\n    usleep(request->message_interval() * 1000);\n    writer->Write(response);\n  }\n  return Status::OK;\n}\n\nStatus EchoServiceImpl::ServerStreamingEchoAbort(\n    ServerContext* context, const ServerStreamingEchoRequest* request,\n    ServerWriter<ServerStreamingEchoResponse>* writer) {\n  CopyClientMetadataToResponse(context);\n  ServerStreamingEchoResponse response;\n  response.set_message(request->message());\n  writer->Write(response);\n  return Status(grpc::StatusCode::ABORTED,\n                \"Aborted from server side.\");\n}\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/echo_service_impl.h",
    "content": "#ifndef NET_GRPC_GATEWAY_EXAMPLES_ECHO_ECHO_SERVICE_IMPL_H_\n#define NET_GRPC_GATEWAY_EXAMPLES_ECHO_ECHO_SERVICE_IMPL_H_\n\n/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n#include <grpcpp/grpcpp.h>\n#include <unistd.h>\n#include <string>\n\n#include \"net/grpc/gateway/examples/echo/echo.grpc.pb.h\"\n\nclass EchoServiceImpl final :\n    public grpc::gateway::testing::EchoService::Service {\n public:\n  EchoServiceImpl();\n  ~EchoServiceImpl() override;\n\n  void CopyClientMetadataToResponse(grpc::ServerContext* context);\n  grpc::Status Echo(\n      grpc::ServerContext* context,\n      const grpc::gateway::testing::EchoRequest* request,\n      grpc::gateway::testing::EchoResponse* response) override;\n  grpc::Status EchoAbort(\n      grpc::ServerContext* context,\n      const grpc::gateway::testing::EchoRequest* request,\n      grpc::gateway::testing::EchoResponse* response) override;\n  grpc::Status NoOp(\n      grpc::ServerContext* context,\n      const grpc::gateway::testing::Empty* request,\n      grpc::gateway::testing::Empty* response) override;\n  grpc::Status ServerStreamingEcho(\n      grpc::ServerContext* context,\n      const grpc::gateway::testing::ServerStreamingEchoRequest* request,\n      grpc::ServerWriter<\n      grpc::gateway::testing::ServerStreamingEchoResponse>* writer) override;\n  grpc::Status ServerStreamingEchoAbort(\n      grpc::ServerContext* context,\n      const grpc::gateway::testing::ServerStreamingEchoRequest* request,\n      grpc::ServerWriter<\n      grpc::gateway::testing::ServerStreamingEchoResponse>* writer) override;\n};\n\n#endif  // NET_GRPC_GATEWAY_EXAMPLES_ECHO_ECHO_SERVICE_IMPL_H_\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/echoapp.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nconst echoapp = {};\n\n/**\n * @param {Object} echoService\n * @param {Object} ctors\n */\nechoapp.EchoApp = function(echoService, ctors) {\n  this.echoService = echoService;\n  this.ctors = ctors;\n};\n\nechoapp.EchoApp.INTERVAL = 500; // ms\nechoapp.EchoApp.MAX_STREAM_MESSAGES = 50;\n\n/**\n * @param {string} message\n * @param {string} cssClass\n */\nechoapp.EchoApp.addMessage = function(message, cssClass) {\n  $(\"#first\").after(\n    $(\"<div/>\").addClass(\"row\").append(\n      $(\"<h2/>\").append(\n        $(\"<span/>\").addClass(\"label \" + cssClass).text(message))));\n};\n\n/**\n * @param {string} message\n */\nechoapp.EchoApp.addLeftMessage = function(message) {\n  this.addMessage(message, \"label-primary pull-left\");\n};\n\n/**\n * @param {string} message\n */\nechoapp.EchoApp.addRightMessage = function(message) {\n  this.addMessage(message, \"label-default pull-right\");\n};\n\n/**\n * @param {string} msg\n */\nechoapp.EchoApp.prototype.echo = function(msg) {\n  echoapp.EchoApp.addLeftMessage(msg);\n  var unaryRequest = new this.ctors.EchoRequest();\n  unaryRequest.setMessage(msg);\n  var call = this.echoService.echo(unaryRequest,\n                                   {\"custom-header-1\": \"value1\"},\n                                   function(err, response) {\n    if (err) {\n      echoapp.EchoApp.addRightMessage('Error code: '+err.code+' \"'+\n                                      err.message+'\"');\n    } else {\n      setTimeout(function () {\n        echoapp.EchoApp.addRightMessage(response.getMessage());\n      }, echoapp.EchoApp.INTERVAL);\n    }\n  });\n  call.on('status', function(status) {\n    if (status.metadata) {\n      console.log(\"Received metadata\");\n      console.log(status.metadata);\n    }\n  });\n};\n\n/**\n * @param {string} msg\n */\nechoapp.EchoApp.prototype.echoError = function(msg) {\n  echoapp.EchoApp.addLeftMessage(`Error: ${msg}`);\n  var unaryRequest = new this.ctors.EchoRequest();\n  unaryRequest.setMessage(msg);\n  this.echoService.echoAbort(unaryRequest, {}, function(err, response) {\n    if (err) {\n      echoapp.EchoApp.addRightMessage('Error code: '+err.code+' \"'+\n                                      err.message+'\"');\n    }\n  });\n};\n\n/**\n * @param {string} msg\n * @param {number} count\n */\nechoapp.EchoApp.prototype.repeatEcho = function(msg, count) {\n  echoapp.EchoApp.addLeftMessage(msg);\n  if (count > echoapp.EchoApp.MAX_STREAM_MESSAGES) {\n    count = echoapp.EchoApp.MAX_STREAM_MESSAGES;\n  }\n  var streamRequest = new this.ctors.ServerStreamingEchoRequest();\n  streamRequest.setMessage(msg);\n  streamRequest.setMessageCount(count);\n  streamRequest.setMessageInterval(echoapp.EchoApp.INTERVAL);\n\n  var stream = this.echoService.serverStreamingEcho(\n    streamRequest,\n    {\"custom-header-1\": \"value1\"});\n  stream.on('data', function(response) {\n    echoapp.EchoApp.addRightMessage(response.getMessage());\n  });\n  stream.on('status', function(status) {\n    if (status.metadata) {\n      console.log(\"Received metadata\");\n      console.log(status.metadata);\n    }\n  });\n  stream.on('error', function(err) {\n    echoapp.EchoApp.addRightMessage('Error code: '+err.code+' \"'+\n                                    err.message+'\"');\n  });\n  stream.on('end', function() {\n    console.log(\"stream end signal received\");\n  });\n};\n\n/**\n * @param {Object} e event\n * @return {boolean} status\n */\nechoapp.EchoApp.prototype.send = function(e) {\n  var msg = $(\"#msg\").val().trim();\n  $(\"#msg\").val(''); // clear the text box\n  if (!msg) return false;\n\n  if (msg.indexOf(' ') > 0) {\n    var count = msg.substr(0, msg.indexOf(' '));\n    if (/^\\d+$/.test(count)) {\n      this.repeatEcho(msg.substr(msg.indexOf(' ') + 1), count);\n    } else if (count == 'err') {\n      this.echoError(msg.substr(msg.indexOf(' ') + 1));\n    } else {\n      this.echo(msg);\n    }\n  } else {\n    this.echo(msg);\n  }\n\n  return false;\n};\n\n/**\n * Load the app\n */\nechoapp.EchoApp.prototype.load = function() {\n  var self = this;\n  $(document).ready(function() {\n    // event handlers\n    $(\"#send\").click(self.send.bind(self));\n    $(\"#msg\").keyup(function (e) {\n      if (e.keyCode == 13) self.send(); // enter key\n      return false;\n    });\n\n    $(\"#msg\").focus();\n  });\n};\n\nmodule.exports = echoapp;\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/echotest.html",
    "content": "<!-- Copyright 2018 Google LLC  -->\n\n<!-- Licensed under the Apache License, Version 2.0 (the \"License\");  -->\n<!-- you may not use this file except in compliance with the License.  -->\n<!-- You may obtain a copy of the License at  -->\n\n<!--     https://www.apache.org/licenses/LICENSE-2.0  -->\n\n<!-- Unless required by applicable law or agreed to in writing, software  -->\n<!-- distributed under the License is distributed on an \"AS IS\" BASIS,  -->\n<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  -->\n<!-- See the License for the specific language governing permissions and  -->\n<!-- limitations under the License.  -->\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>Echo Example</title>\n<link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\">\n<script src=\"//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>\n<script type=\"text/javascript\">\nconst module = {};\n</script>\n<script src=\"./echo_js_bin_dev.js\"></script>\n<script src=\"./echoapp.js\"></script>\n<script type=\"text/javascript\">\n var EchoServiceClient = proto.grpc.gateway.testing.EchoServiceClient;\n var echoService = new EchoServiceClient('http://localhost:8080', null, null);\n var echoApp = new echoapp.EchoApp(\n   echoService,\n   {\n     EchoRequest: proto.grpc.gateway.testing.EchoRequest,\n     ServerStreamingEchoRequest: proto.grpc.gateway.testing.ServerStreamingEchoRequest\n   }\n );\n echoApp.load();\n</script>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"row\" id=\"first\">\n      <div class=\"form-group\">\n        <div class=\"input-group\">\n          <input type=\"text\" class=\"form-control\" id=\"msg\">\n          <span class=\"input-group-btn\">\n            <button class=\"btn btn-primary\" type=\"button\" id=\"send\">Send\n            </button>\n          </span>\n        </div>\n        <p class=\"help-block\">Example: \"Hello\", \"4 Hello\", \"err Hello\"</p>\n      </div>\n    </div>\n  </div>\n</body>\n</html>\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/envoy.yaml",
    "content": "admin:\n  access_log_path: /tmp/admin_access.log\n  address:\n    socket_address: { address: 0.0.0.0, port_value: 9901 }\n\nstatic_resources:\n  listeners:\n    - name: listener_0\n      address:\n        socket_address: { address: 0.0.0.0, port_value: 8080 }\n      filter_chains:\n        - filters:\n          - name: envoy.filters.network.http_connection_manager\n            typed_config:\n              \"@type\": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager\n              codec_type: auto\n              stat_prefix: ingress_http\n              route_config:\n                name: local_route\n                virtual_hosts:\n                  - name: local_service\n                    domains: [\"*\"]\n                    routes:\n                      - match: { prefix: \"/\" }\n                        route:\n                          cluster: echo_service\n                          timeout: 0s\n                          max_stream_duration:\n                            grpc_timeout_header_max: 0s\n                    cors:\n                      allow_origin_string_match:\n                        - prefix: \"*\"\n                      allow_methods: GET, PUT, DELETE, POST, OPTIONS\n                      allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout\n                      max_age: \"1728000\"\n                      expose_headers: custom-header-1,grpc-status,grpc-message\n              http_filters:\n                - name: envoy.filters.http.grpc_web\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb\n                - name: envoy.filters.http.cors\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors\n                - name: envoy.filters.http.router\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router\n  clusters:\n    - name: echo_service\n      connect_timeout: 0.25s\n      type: logical_dns\n      # HTTP/2 support\n      typed_extension_protocol_options:\n        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:\n          \"@type\": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions\n          explicit_http_config:\n            http2_protocol_options: {}\n      lb_policy: round_robin\n      load_assignment:\n        cluster_name: cluster_0\n        endpoints:\n          - lb_endpoints:\n            - endpoint:\n                address:\n                  socket_address:\n                    address: node-server\n                    port_value: 9090\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/node-server/.gitignore",
    "content": "node_modules/\npackage-lock.json\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/node-server/package.json",
    "content": "{\n  \"name\": \"grpc-web-node-server-example\",\n  \"version\": \"0.1.0\",\n  \"main\": \"server.js\",\n  \"dependencies\": {\n    \"@grpc/grpc-js\": \"1.13.4\",\n    \"@grpc/proto-loader\": \"~0.5.0\",\n    \"async\": \"~3.2.3\",\n    \"google-protobuf\": \"~3.21.4\",\n    \"lodash\": \"~4.17.0\"\n  }\n}\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/node-server/server.js",
    "content": "/*\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nvar PROTO_PATH = __dirname + '/../echo.proto';\n\nvar assert = require('assert');\nvar async = require('async');\nvar _ = require('lodash');\nvar grpc = require('@grpc/grpc-js');\nvar protoLoader = require('@grpc/proto-loader');\nvar packageDefinition = protoLoader.loadSync(\n    PROTO_PATH,\n    {keepCase: true,\n     longs: String,\n     enums: String,\n     defaults: true,\n     oneofs: true\n    });\nvar protoDescriptor = grpc.loadPackageDefinition(packageDefinition);\nvar echo = protoDescriptor.grpc.gateway.testing;\n\n/**\n * @param {!Object} call\n * @return {!Object} metadata\n */\nfunction copyMetadata(call) {\n  var metadata = call.metadata.getMap();\n  var response_metadata = new grpc.Metadata();\n  for (var key in metadata) {\n    response_metadata.set(key, metadata[key]);\n  }\n  return response_metadata;\n}\n\n/**\n * @param {!Object} call\n * @param {function():?} callback\n */\nfunction doEcho(call, callback) {\n  callback(null, {\n    message: call.request.message\n  }, copyMetadata(call));\n}\n\n/**\n * @param {!Object} call\n * @param {function():?} callback\n */\nfunction doEchoAbort(call, callback) {\n  callback({\n    code: grpc.status.ABORTED,\n    message: 'Aborted from server side.'\n  });\n}\n\n/**\n * @param {!Object} call\n */\nfunction doServerStreamingEcho(call) {\n  var senders = [];\n  function sender(message, interval) {\n    return (callback) => {\n      call.write({\n        message: message\n      });\n      _.delay(callback, interval);\n    };\n  }\n  for (var i = 0; i < call.request.message_count; i++) {\n    senders[i] = sender(call.request.message, call.request.message_interval);\n  }\n  async.series(senders, () => {\n    call.end(copyMetadata(call));\n  });\n}\n\n/**\n * Get a new server with the handler functions in this file bound to the\n * methods it serves.\n * @return {!Server} The new server object\n */\nfunction getServer() {\n  var server = new grpc.Server();\n  server.addService(echo.EchoService.service, {\n    echo: doEcho,\n    echoAbort: doEchoAbort,\n    serverStreamingEcho: doServerStreamingEcho,\n  });\n  return server;\n}\n\nif (require.main === module) {\n  var echoServer = getServer();\n  echoServer.bindAsync(\n    '0.0.0.0:9090', grpc.ServerCredentials.createInsecure(), (err, port) => {\n      assert.ifError(err);\n      echoServer.start();\n  });\n}\n\nexports.getServer = getServer;\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/package.json",
    "content": "{\n    \"name\": \"echo-closure-example\",\n    \"version\": \"0.1.0\",\n    \"description\": \"gRPC-Web Closure JS client example\",\n    \"license\": \"Apache-2.0\",\n    \"dependencies\": {},\n    \"devDependencies\": {\n        \"google-closure-compiler\": \"~20200224.0.0\",\n        \"google-closure-library\": \"~20210808.0.0\"\n    }\n}\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/ts-example/.gitignore",
    "content": "dist/\nnode_modules/\npackage-lock.json\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/ts-example/README.md",
    "content": "# Instructions to run the Typescript example\n\n## Docker run\n\n```bash\n# From root dir\ndocker-compose up --build node-server envoy ts-client\n```\n\nVisit http://localhost:8081/echotest.html\n\n## Manual run\n\n### Step 1 - Run servers\n\n```bash\n# From root dir\ndocker-compose up --build node-server envoy\n```\n\n### Step 2 - Codegen\n```bash\ncd net/grpc/gateway/examples/echo\n```\n\n#### Option 1: `import_style=commonjs+dts`\n\n```\nRUN protoc -I=. echo.proto \\\n  --js_out=import_style=commonjs:./ts-example \\\n  --grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:./ts-example\n```\n\n#### Option 2: `import_style=typescript`\n\n```\nRUN protoc -I=. echo.proto \\\n  --js_out=import_style=commonjs:./ts-example \\\n  --grpc-web_out=import_style=typescript,mode=grpcwebtext:./ts-example\n```\n\n### Step 3 - (Optional) Update import style\n\nChange `client.ts` to use import style Option 2 if you had chosen `import_style=typescript` above:\n\nhttps://github.com/grpc/grpc-web/blob/60caece15489787662ebac6167572eecd5bfa568/net/grpc/gateway/examples/echo/ts-example/client.ts#L26-L27\n\n### Step 4 - Build JS files.\n\n```bash\ncd net/grpc/gateway/examples/echo/ts-example\nnpm install\nnpx tsc\nmv *_pb.js dist/\nnpx webpack\n```\n\n### Step 5 - Host and visit page\n\n```bash\n# In the ./ts-example folder\npython3 -m http.server 8081\n```\n\nVisit http://localhost:8081/echotest.html"
  },
  {
    "path": "net/grpc/gateway/examples/echo/ts-example/client.ts",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nimport * as grpcWeb from 'grpc-web';\nimport * as $ from 'jquery';\n\n// Uncomment either one of the following:\n// Option 1: import_style=commonjs+dts\nimport {EchoServiceClient} from './echo_grpc_web_pb';\n\n// Option 2: import_style=typescript\n// import {EchoServiceClient} from './EchoServiceClientPb';\n\nimport {EchoRequest, EchoResponse, ServerStreamingEchoRequest, ServerStreamingEchoResponse} from './echo_pb';\n\nclass EchoApp {\n  static readonly INTERVAL = 500;  // ms\n  static readonly MAX_STREAM_MESSAGES = 50;\n\n  stream?: grpcWeb.ClientReadableStream<ServerStreamingEchoResponse>;\n\n  constructor(public echoService: EchoServiceClient) {}\n\n  static addMessage(message: string, cssClass: string) {\n    $('#first').after($('<div/>').addClass('row').append($('<h2/>').append(\n        $('<span/>').addClass('label ' + cssClass).text(message))));\n  }\n\n  static addLeftMessage(message: string) {\n    this.addMessage(message, 'label-primary pull-left');\n  }\n\n  static addRightMessage(message: string) {\n    this.addMessage(message, 'label-default pull-right');\n  }\n\n  echo(msg: string) {\n    EchoApp.addLeftMessage(msg);\n    const request = new EchoRequest();\n    request.setMessage(msg);\n    const call = this.echoService.echo(\n        request, {'custom-header-1': 'value1'},\n        (err: grpcWeb.RpcError, response: EchoResponse) => {\n          if (err) {\n            if (err.code !== grpcWeb.StatusCode.OK) {\n              EchoApp.addRightMessage(\n                  'Error code: ' + err.code + ' \"' + err.message + '\"');\n            }\n          } else {\n            setTimeout(() => {\n              EchoApp.addRightMessage(response.getMessage());\n            }, EchoApp.INTERVAL);\n          }\n        });\n    call.on('status', (status: grpcWeb.Status) => {\n      if (status.metadata) {\n        console.log('Received metadata');\n        console.log(status.metadata);\n      }\n    });\n  }\n\n  echoError(msg: string) {\n    EchoApp.addLeftMessage(`Error: ${msg}`);\n    const request = new EchoRequest();\n    request.setMessage(msg);\n    this.echoService.echoAbort(\n        request, {}, (err: grpcWeb.RpcError, response: EchoResponse) => {\n          if (err && err.code !== grpcWeb.StatusCode.OK) {\n            EchoApp.addRightMessage(\n                'Error code: ' + err.code + ' \"' + decodeURI(err.message) +\n                '\"');\n          }\n        });\n  }\n\n  cancel() {\n    EchoApp.addLeftMessage('Cancel');\n    if (this.stream) {\n      this.stream.cancel();\n    }\n  }\n\n  repeatEcho(msg: string, count: number) {\n    EchoApp.addLeftMessage(msg);\n    if (count > EchoApp.MAX_STREAM_MESSAGES) {\n      count = EchoApp.MAX_STREAM_MESSAGES;\n    }\n    const request = new ServerStreamingEchoRequest();\n    request.setMessage(msg);\n    request.setMessageCount(count);\n    request.setMessageInterval(EchoApp.INTERVAL);\n\n    this.stream = this.echoService.serverStreamingEcho(\n        request, {'custom-header-1': 'value1'});\n    const self = this;\n    this.stream.on('data', (response: ServerStreamingEchoResponse) => {\n      EchoApp.addRightMessage(response.getMessage());\n    });\n    this.stream.on('status', (status: grpcWeb.Status) => {\n      if (status.metadata) {\n        console.log('Received metadata');\n        console.log(status.metadata);\n      }\n    });\n    this.stream.on('error', (err: grpcWeb.RpcError) => {\n      EchoApp.addRightMessage(\n          'Error code: ' + err.code + ' \"' + err.message + '\"');\n    });\n    this.stream.on('end', () => {\n      console.log('stream end signal received');\n    });\n  }\n\n  send(e: {}) {\n    const _msg: string = $('#msg').val() as string;\n    const msg = _msg.trim();\n    $('#msg').val('');  // clear the text box\n    if (!msg) return false;\n\n    if (msg.indexOf(' ') > 0) {\n      const count = msg.substr(0, msg.indexOf(' '));\n      if (/^\\d+$/.test(count)) {\n        this.repeatEcho(msg.substr(msg.indexOf(' ') + 1), Number(count));\n      } else if (count === 'err') {\n        this.echoError(msg.substr(msg.indexOf(' ') + 1));\n      } else {\n        this.echo(msg);\n      }\n    } else if (msg === 'cancel') {\n      this.cancel();\n    } else {\n      this.echo(msg);\n    }\n  }\n\n  load() {\n    const self = this;\n    $(document).ready(() => {\n      // event handlers\n      $('#send').click(self.send.bind(self));\n      $('#msg').keyup((e) => {\n        if (e.keyCode === 13) self.send(e);  // enter key\n        return false;\n      });\n\n      $('#msg').focus();\n    });\n  }\n}\n\nconst echoService = new EchoServiceClient('http://localhost:8080', null, null);\n\nconst echoApp = new EchoApp(echoService);\nechoApp.load();\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/ts-example/echotest.html",
    "content": "<!-- Copyright 2018 Google LLC  -->\n\n<!-- Licensed under the Apache License, Version 2.0 (the \"License\");  -->\n<!-- you may not use this file except in compliance with the License.  -->\n<!-- You may obtain a copy of the License at  -->\n\n<!--     https://www.apache.org/licenses/LICENSE-2.0  -->\n\n<!-- Unless required by applicable law or agreed to in writing, software  -->\n<!-- distributed under the License is distributed on an \"AS IS\" BASIS,  -->\n<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  -->\n<!-- See the License for the specific language governing permissions and  -->\n<!-- limitations under the License.  -->\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>Echo Example</title>\n<link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\">\n<script src=\"//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>\n<script>\n  // Load the local /dist/main.js and use a random query parameter to disable caching.\n  const script = document.createElement('script');\n  script.src = `./dist/main.js?v=${Date.now()}`;\n  document.head.appendChild(script);\n</script>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"row\" id=\"first\">\n      <div class=\"form-group\">\n        <div class=\"input-group\">\n          <input type=\"text\" class=\"form-control\" id=\"msg\">\n          <span class=\"input-group-btn\">\n            <button class=\"btn btn-primary\" type=\"button\" id=\"send\">Send\n            </button>\n          </span>\n        </div>\n        <p class=\"help-block\">Example: \"Hello\", \"4 Hello\", \"err Hello\"</p>\n      </div>\n    </div>\n  </div>\n</body>\n</html>\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/ts-example/package.json",
    "content": "{\n  \"devDependencies\": {\n    \"@types/google-protobuf\": \"~3.15.12\",\n    \"@types/jquery\": \"~3.3.6\",\n    \"@types/node\": \"latest\",\n    \"google-protobuf\": \"~3.21.4\",\n    \"grpc-web\": \"~2.0.2\",\n    \"jquery\": \"~3.5.1\",\n    \"mock-xmlhttprequest\": \"~2.0.0\",\n    \"typescript\": \"latest\",\n    \"webpack\": \"5.101.3\",\n    \"webpack-cli\": \"~5.1.1\"\n  }\n}\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/ts-example/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es6\",\n    \"module\": \"commonjs\",\n    \"strict\": true,\n    \"allowJs\": true,\n    \"outDir\": \"./dist\",\n    \"types\": [\"node\"],\n  },\n  \"include\": [\n    \"client.ts\",\n    \"echo_pb.js\",\n    \"echo_pb.d.ts\",\n    \"echo_grpc_web_pb.js\",\n    \"echo_grpc_web_pb.d.ts\",\n    \"EchoServiceClientPb.ts\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ]\n}\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/ts-example/webpack.config.js",
    "content": "module.exports = {\n  mode: 'production',\n  entry: './dist/client.js',\n};\n"
  },
  {
    "path": "net/grpc/gateway/examples/echo/tutorial.md",
    "content": "This tutorial provides a detailed guide on how to run a gRPC service and access\nit in the browser.\n\n\n## Define the Service\n\nThe first step when creating a gRPC service is to define the service methods\nand their request and response message types using protocol buffers. In this\nexample, we define our `EchoService` in a file called\n[`echo.proto`](echo.proto). For more information about protocol buffers and\nproto3 syntax, please see the [protobuf documentation][].\n\n```protobuf\nmessage EchoRequest {\n  string message = 1;\n}\n\nmessage EchoResponse {\n  string message = 1;\n}\n\nservice EchoService {\n  rpc Echo(EchoRequest) returns (EchoResponse);\n}\n```\n\n## Implement gRPC Backend Server\n\nNext, we implement our EchoService interface using Node in the backend gRPC\n`EchoServer`. This will handle requests from clients. See the file\n[`node-server/server.js`](./node-server/server.js) for details.\n\nYou can implement the server in any language supported by gRPC. Please see\nthe [gRPC website][] for more details.\n\n```js\nfunction doEcho(call, callback) {\n  callback(null, {message: call.request.message});\n}\n```\n\n\n## Configure the Envoy Proxy\n\nIn this example, we will use the [Envoy](https://www.envoyproxy.io/)\nproxy to forward the gRPC browser request to the backend server. You can see\nthe complete config file in [envoy.yaml](./envoy.yaml)\n\nTo forward the gRPC requests to the backend server, we need a block like\nthis:\n\n```yaml\nstatic_resources:\n  listeners:\n    - name: listener_0\n      address:\n        socket_address: { address: 0.0.0.0, port_value: 8080 }\n      filter_chains:\n        - filters:\n          - name: envoy.filters.network.http_connection_manager\n            typed_config:\n              \"@type\": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager\n              codec_type: auto\n              stat_prefix: ingress_http\n              route_config:\n                name: local_route\n                virtual_hosts:\n                  - name: local_service\n                    domains: [\"*\"]\n                    routes:\n                      - match: { prefix: \"/\" }\n                        route:\n                          cluster: echo_service\n                          timeout: 0s\n              http_filters:\n                - name: envoy.filters.http.grpc_web\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb\n                - name: envoy.filters.http.router\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router\n  clusters:\n    - name: echo_service\n      connect_timeout: 0.25s\n      type: logical_dns\n      # HTTP/2 support\n      typed_extension_protocol_options:\n        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:\n          \"@type\": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions\n          explicit_http_config:\n            http2_protocol_options: {}\n      lb_policy: round_robin\n      load_assignment:\n        cluster_name: cluster_0\n        endpoints:\n          - lb_endpoints:\n            - endpoint:\n                address:\n                  socket_address:\n                    address: node-server\n                    port_value: 9090\n```\n\nYou may also need to add some CORS setup to make sure the browser can request\ncross-origin content.\n\n\nIn this simple example, the browser makes gRPC requests to port `:8080`. Envoy\nforwards the request to the backend gRPC server listening on port `:9090`.\n\n\n\n## Generate Protobuf Messages and Service Client Stub\n\n\nTo generate the protobuf message classes from our `echo.proto`, run the\nfollowing command:\n\n```sh\n$ protoc -I=$DIR echo.proto \\\n  --js_out=import_style=commonjs:$OUT_DIR\n```\n\nThe `import_style` option passed to the `--js_out` flag makes sure the\ngenerated files will have CommonJS style `require()` statements.\n\n\nTo generate the gRPC-Web service client stub, first you need the gRPC-Web\nprotoc plugin. To compile the plugin `protoc-gen-grpc-web`, you need to run\nthis from the repo's root directory:\n\n```sh\n$ cd grpc-web\n$ sudo make install-plugin\n```\n\nTo generate the service client stub file, run this command:\n\n```sh\n$ protoc -I=$DIR echo.proto \\\n  --grpc-web_out=import_style=commonjs,mode=grpcwebtext:$OUT_DIR\n```\n\nIn the `--grpc-web_out` param above:\n  - `mode` can be `grpcwebtext` (default) or `grpcweb`\n  - `import_style` can be `closure` (default) or `commonjs`\n\nOur command generates the client stub, by default, to the file\n`echo_grpc_web_pb.js`.\n\n\n## Write JS Client Code\n\nNow you are ready to write some JS client code. Put this in a `client.js` file.\n\n```js\nconst {EchoRequest, EchoResponse} = require('./echo_pb.js');\nconst {EchoServiceClient} = require('./echo_grpc_web_pb.js');\n\nvar echoService = new EchoServiceClient('http://localhost:8080');\n\nvar request = new EchoRequest();\nrequest.setMessage('Hello World!');\n\nechoService.echo(request, {}, function(err, response) {\n  // ...\n});\n```\n\nYou will need a `package.json` file\n\n```json\n{\n  \"name\": \"grpc-web-commonjs-example\",\n  \"dependencies\": {\n    \"google-protobuf\": \"~3.21.4\",\n    \"grpc-web\": \"~2.0.2\"\n  },\n  \"devDependencies\": {\n    \"webpack\": \"~5.82.1\",\n    \"webpack-cli\": \"~5.1.1\"\n  }\n}\n```\n\n## Compile the JS Library\n\n\nFinally, putting all these together, we can compile all the relevant JS files\ninto one single JS library that can be used in the browser.\n\n```sh\n$ npm install\n$ npx webpack ./client.js\n```\n\nNow embed `dist/main.js` into your project and see it in action!\n\n\n[protobuf documentation]:https://developers.google.com/protocol-buffers/\n[gRPC website]:https://grpc.io\n"
  },
  {
    "path": "net/grpc/gateway/examples/helloworld/.gitignore",
    "content": "dist/\n*_pb.js\nnode_modules/\npackage-lock.json\n"
  },
  {
    "path": "net/grpc/gateway/examples/helloworld/README.md",
    "content": "# gRPC-Web Hello World Guide\n\nThis guide is intended to help you get started with gRPC-Web with a simple\nHello World example. For more information about the gRPC-Web project as a\nwhole, please visit the [main repo](https://github.com/grpc/grpc-web).\n\nAll the code for this example can be found in this current directory.\n\n```sh\n$ cd net/grpc/gateway/examples/helloworld\n```\n\n## Define the Service\n\nFirst, let's define a gRPC service using\n[protocol buffers](https://developers.google.com/protocol-buffers/). Put this\nin the `helloworld.proto` file. Here we define a request message, a response\nmessage, and a service with one RPC method: `SayHello`.\n\n```protobuf\nsyntax = \"proto3\";\n\npackage helloworld;\n\nservice Greeter {\n  rpc SayHello (HelloRequest) returns (HelloReply);\n}\n\nmessage HelloRequest {\n  string name = 1;\n}\n\nmessage HelloReply {\n  string message = 1;\n}\n```\n\n## Implement the Service\n\nThen, we need to implement the gRPC Service. In this example, we will use\nNodeJS. Put this in a `server.js` file. Here, we receive the client request,\nand we can access the message field via `call.request.name`. Then we construct\na nice response and send it back to the client via `callback(null, response)`.\n\n```js\nvar PROTO_PATH = __dirname + '/helloworld.proto';\n\nvar assert = require('assert');\nvar grpc = require('@grpc/grpc-js');\nvar protoLoader = require('@grpc/proto-loader');\nvar packageDefinition = protoLoader.loadSync(\n    PROTO_PATH,\n    {keepCase: true,\n     longs: String,\n     enums: String,\n     defaults: true,\n     oneofs: true\n    });\nvar protoDescriptor = grpc.loadPackageDefinition(packageDefinition);\nvar helloworld = protoDescriptor.helloworld;\n\nfunction doSayHello(call, callback) {\n  callback(null, {\n    message: 'Hello! ' + call.request.name\n  });\n}\n\nfunction getServer() {\n  var server = new grpc.Server();\n  server.addService(helloworld.Greeter.service, {\n    sayHello: doSayHello,\n  });\n  return server;\n}\n\nif (require.main === module) {\n  var server = getServer();\n  server.bindAsync(\n    '0.0.0.0:9090', grpc.ServerCredentials.createInsecure(), (err, port) => {\n      assert.ifError(err);\n      server.start();\n  });\n}\n\nexports.getServer = getServer;\n```\n\n## Configure the Proxy\n\nNext up, we need to configure the Envoy proxy to forward the browser's gRPC-Web\nrequests to the backend. Put this in an `envoy.yaml` file. Here we configure\nEnvoy to listen at port `:8080`, and forward any gRPC-Web requests to a\ncluster at port `:9090`.\n\n```yaml\nstatic_resources:\n  listeners:\n    - name: listener_0\n      address:\n        socket_address: { address: 0.0.0.0, port_value: 8080 }\n      filter_chains:\n        - filters:\n          - name: envoy.filters.network.http_connection_manager\n            typed_config:\n              \"@type\": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager\n              codec_type: auto\n              stat_prefix: ingress_http\n              route_config:\n                name: local_route\n                virtual_hosts:\n                  - name: local_service\n                    domains: [\"*\"]\n                    routes:\n                      - match: { prefix: \"/\" }\n                        route:\n                          cluster: greeter_service\n                          max_stream_duration:\n                            grpc_timeout_header_max: 0s\n                    cors:\n                      allow_origin_string_match:\n                        - prefix: \"*\"\n                      allow_methods: GET, PUT, DELETE, POST, OPTIONS\n                      allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout\n                      max_age: \"1728000\"\n                      expose_headers: custom-header-1,grpc-status,grpc-message\n              http_filters:\n                - name: envoy.filters.http.grpc_web\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb\n                - name: envoy.filters.http.cors\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors\n                - name: envoy.filters.http.router\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router\n  clusters:\n    - name: greeter_service\n      connect_timeout: 0.25s\n      type: logical_dns\n      # HTTP/2 support\n      typed_extension_protocol_options:\n        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:\n          \"@type\": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions\n          explicit_http_config:\n            http2_protocol_options: {}\n      lb_policy: round_robin\n      load_assignment:\n        cluster_name: cluster_0\n        endpoints:\n          - lb_endpoints:\n            - endpoint:\n                address:\n                  socket_address:\n                    address: 0.0.0.0\n                    port_value: 9090\n```\n\n> NOTE: As per [this issue](https://github.com/grpc/grpc-web/issues/436): if\n> you are running Docker on Mac/Windows, change the last `address: 0.0.0.0` to\n>\n> ```yaml\n>     ...\n>     socket_address:\n>         address: host.docker.internal\n> ```\n>\n> or if your version of Docker on Mac is older than v18.03.0, change it to:\n>\n> ```yaml\n>     ...\n>     socket_address:\n>         address: docker.for.mac.localhost\n> ```\n\n> NOTE: As per\n> [Envoy - Envoy Networking](ttps://www.envoyproxy.io/docs/envoy/latest/start/quick-start/run-envoy#envoy-networking),\n> if your environment does not enable IPv6, enable only IPv4 in the cluster\n> by adding the `dns_lookup_family: V4_ONLY` field:\n>\n> ```yaml\n>     ...\n>     clusters:\n>       - name: greeter_service\n>       dns_lookup_family: V4_ONLY\n> ```\n\n## Write Client Code\n\nNow, we are ready to write some client code! Put this in a `client.js` file.\n\n```js\nconst {HelloRequest, HelloReply} = require('./helloworld_pb.js');\nconst {GreeterClient} = require('./helloworld_grpc_web_pb.js');\n\nvar client = new GreeterClient('http://localhost:8080');\n\nvar request = new HelloRequest();\nrequest.setName('World');\n\nclient.sayHello(request, {}, (err, response) => {\n  console.log(response.getMessage());\n});\n```\n\nThe classes `HelloRequest`, `HelloReply` and `GreeterClient` we import here are\ngenerated for you by the `protoc` generator utility (which we will cover in the\nnext section) from the `helloworld.proto` file we defined earlier.\n\nThen we instantiate a `GreeterClient` instance, set the field in the\n`HelloRequest` protobuf object, and we can make a gRPC call via\n`client.sayHello()`, just like how we defined in the `helloworld.proto` file.\n\n\nYou will need a `package.json` file. This is needed for both the `server.js` and\nthe `client.js` files.\n\n```json\n{\n  \"name\": \"grpc-web-simple-example\",\n  \"version\": \"0.1.0\",\n  \"description\": \"gRPC-Web simple example\",\n  \"main\": \"server.js\",\n  \"devDependencies\": {\n    \"@grpc/grpc-js\": \"~1.0.5\",\n    \"@grpc/proto-loader\": \"~0.5.4\",\n    \"async\": \"~1.5.2\",\n    \"google-protobuf\": \"~3.21.4\",\n    \"grpc-web\": \"~2.0.2\",\n    \"lodash\": \"~4.17.0\",\n    \"webpack\": \"~5.82.1\",\n    \"webpack-cli\": \"~5.1.1\"\n  }\n}\n```\n\nAnd finally a simple `index.html` file.\n\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>gRPC-Web Example</title>\n<script src=\"./dist/main.js\"></script>\n</head>\n<body>\n  <p>Open up the developer console and see the logs for the output.</p>\n</body>\n</html>\n```\n\nThe `./dist/main.js` file will be generated by `webpack` (which will be covered\nin the next section).\n\n\nAnd that's it! We have all the code ready. Let's run the example!\n\n## Generate Protobuf Messages and Client Service Stub\n\n### Install Plugins\n\nTo generate the protobuf messages and client service stub class from your\n`.proto` definitions, we need:\n - the `protoc` binary, _and_\n - the `protoc-gen-js` binary, _and_\n - the `protoc-gen-grpc-web` plugin.\n\nFollow the instructions [here](https://github.com/grpc/grpc-web?tab=readme-ov-file#code-generator-plugins)\nif you don't have them installed already.\n\n### Generating stubs\n\nWhen you have both `protoc`, `protoc-gen-js`, and `protoc-gen-grpc-web`\ninstalled, you can now run this command:\n\n```sh\n$ protoc -I=. helloworld.proto \\\n  --js_out=import_style=commonjs:. \\\n  --grpc-web_out=import_style=commonjs,mode=grpcwebtext:.\n```\n\nAfter the command runs successfully, you should now see two new files generated\nin the current directory:\n\n - `helloworld_pb.js`: this contains the `HelloRequest` and `HelloReply`\n   classes\n - `helloworld_grpc_web_pb.js`: this contains the `GreeterClient` class\n\nThese are also the 2 files that our `client.js` file imported earlier in the\nexample.\n\n## Compile the Client JavaScript Code\n\nNext, we need to compile the client side JavaScript code into something that\ncan be consumed by the browser.\n\n```sh\n$ npm install\n$ npx webpack ./client.js\n```\n\nHere we use `webpack` and give it an entry point `client.js`. You can also use\n`browserify` or other similar tools. This will resolve all the `require()`\nstatements and produce a `./dist/main.js` file that can be embedded in our\n`index.html` file.\n\n## Run the Example!\n\nWe are ready to run the Hello World example. The following set of commands will\nrun the 3 processes all in the background.\n\n 1. Run the NodeJS gRPC Service. This listens at port `:9090`.\n\n ```sh\n $ node server.js &\n ```\n\n 2. Run the Envoy proxy. The `envoy.yaml` file configures Envoy to listen to\n browser requests at port `:8080`, and forward them to port `:9090` (see\n above).\n\n ```sh\n $ docker run -d -v \"$(pwd)\"/envoy.yaml:/etc/envoy/envoy.yaml:ro \\\n     --network=host envoyproxy/envoy:v1.22.0\n ```\n\n> NOTE: As per [this issue](https://github.com/grpc/grpc-web/issues/436):\n> if you are running Docker on Mac/Windows, remove the `--network=host` option:\n>\n> ```sh\n> $ docker run -d -v \"$(pwd)\"/envoy.yaml:/etc/envoy/envoy.yaml:ro \\\n>     -p 8080:8080 -p 9901:9901 envoyproxy/envoy:v1.22.0\n>  ```\n\n 3. Run the simple Web Server. This hosts the static file `index.html` and\n `dist/main.js` we generated earlier.\n\n ```sh\n $ python3 -m http.server 8081 &\n ```\n\nWhen these are all ready, you can open a browser tab and navigate to\n\n```\nlocalhost:8081\n```\n\nOpen up the developer console and you should see the following printed out:\n\n```\nHello! World\n```\n"
  },
  {
    "path": "net/grpc/gateway/examples/helloworld/client.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nconst {HelloRequest, RepeatHelloRequest,\n       HelloReply} = require('./helloworld_pb.js');\nconst {GreeterClient} = require('./helloworld_grpc_web_pb.js');\n\nvar client = new GreeterClient('http://' + window.location.hostname + ':8080',\n                               null, null);\n\n// simple unary call\nvar request = new HelloRequest();\nrequest.setName('World');\n\nclient.sayHello(request, {}, (err, response) => {\n  if (err) {\n    console.log(`Unexpected error for sayHello: code = ${err.code}` +\n                `, message = \"${err.message}\"`);\n  } else {\n    console.log(response.getMessage());\n  }\n});\n\n\n// server streaming call\nvar streamRequest = new RepeatHelloRequest();\nstreamRequest.setName('World');\nstreamRequest.setCount(5);\n\nvar stream = client.sayRepeatHello(streamRequest, {});\nstream.on('data', (response) => {\n  console.log(response.getMessage());\n});\nstream.on('error', (err) => {\n  console.log(`Unexpected stream error: code = ${err.code}` +\n              `, message = \"${err.message}\"`);\n});\n"
  },
  {
    "path": "net/grpc/gateway/examples/helloworld/debugging/node-client.js",
    "content": "// NOTE: This client is used for debugging the node gRPC server WITHOUT the\n// Envoy proxy. It does not use the gRPC-Web protocol.\n\nvar PROTO_PATH = __dirname + '/helloworld.proto';\n\nvar async = require('async');\nvar grpc = require('@grpc/grpc-js');\nvar protoLoader = require('@grpc/proto-loader');\nvar packageDefinition = protoLoader.loadSync(\n    PROTO_PATH,\n    {keepCase: true,\n     longs: String,\n     enums: String,\n     defaults: true,\n     oneofs: true\n    });\nvar protoDescriptor = grpc.loadPackageDefinition(packageDefinition);\nvar helloworld = protoDescriptor.helloworld;\nvar client = new helloworld.Greeter('localhost:9090',\n                                    grpc.credentials.createInsecure());\n\n/**\n * @param {function():?} callback\n */\nfunction runSayHello(callback) {\n  client.sayHello({name: 'John'}, {}, (err, response) => {\n    console.log(response.message);\n    callback();\n  });\n}\n\n/**\n * @param {function():?} callback\n */\nfunction runSayRepeatHello(callback) {\n  var stream = client.sayRepeatHello({name: 'John', count: 5}, {});\n  stream.on('data', (response) => {\n    console.log(response.message);\n  });\n  stream.on('end', () => {\n    callback();\n  });\n}\n\n\n/**\n * Run all of the demos in order\n */\nfunction main() {\n  async.series([\n    runSayHello,\n    runSayRepeatHello,\n  ]);\n}\n\nif (require.main === module) {\n  main();\n}\n"
  },
  {
    "path": "net/grpc/gateway/examples/helloworld/envoy.yaml",
    "content": "admin:\n  access_log_path: /tmp/admin_access.log\n  address:\n    socket_address: { address: 0.0.0.0, port_value: 9901 }\n\nstatic_resources:\n  listeners:\n    - name: listener_0\n      address:\n        socket_address: { address: 0.0.0.0, port_value: 8080 }\n      filter_chains:\n        - filters:\n          - name: envoy.filters.network.http_connection_manager\n            typed_config:\n              \"@type\": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager\n              codec_type: auto\n              stat_prefix: ingress_http\n              route_config:\n                name: local_route\n                virtual_hosts:\n                  - name: local_service\n                    domains: [\"*\"]\n                    routes:\n                      - match: { prefix: \"/\" }\n                        route:\n                          cluster: greeter_service\n                          timeout: 0s\n                          max_stream_duration:\n                            grpc_timeout_header_max: 0s\n                    cors:\n                      allow_origin_string_match:\n                        - prefix: \"*\"\n                      allow_methods: GET, PUT, DELETE, POST, OPTIONS\n                      allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout\n                      max_age: \"1728000\"\n                      expose_headers: custom-header-1,grpc-status,grpc-message\n              http_filters:\n                - name: envoy.filters.http.grpc_web\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb\n                - name: envoy.filters.http.cors\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors\n                - name: envoy.filters.http.router\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router\n  clusters:\n    - name: greeter_service\n      connect_timeout: 0.25s\n      type: logical_dns\n      # HTTP/2 support\n      typed_extension_protocol_options:\n        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:\n          \"@type\": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions\n          explicit_http_config:\n            http2_protocol_options: {}\n      lb_policy: round_robin\n      # win/mac hosts: Use address: host.docker.internal instead of address: localhost in the line below\n      load_assignment:\n        cluster_name: cluster_0\n        endpoints:\n          - lb_endpoints:\n            - endpoint:\n                address:\n                  socket_address:\n                    address: 0.0.0.0\n                    port_value: 9090\n"
  },
  {
    "path": "net/grpc/gateway/examples/helloworld/helloworld.proto",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     https://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage helloworld;\n\nservice Greeter {\n  // unary call\n  rpc SayHello(HelloRequest) returns (HelloReply);\n  // server streaming call\n  rpc SayRepeatHello(RepeatHelloRequest) returns (stream HelloReply);\n}\n\nmessage HelloRequest {\n  string name = 1;\n}\n\nmessage RepeatHelloRequest {\n  string name = 1;\n  int32 count = 2;\n}\n\nmessage HelloReply {\n  string message = 1;\n}\n"
  },
  {
    "path": "net/grpc/gateway/examples/helloworld/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>gRPC-Web Example</title>\n<script src=\"./dist/main.js\"></script>\n</head>\n<body>\n  <p>Open up the developer console and see the logs for the output.</p>\n</body>\n</html>\n"
  },
  {
    "path": "net/grpc/gateway/examples/helloworld/package.json",
    "content": "{\n  \"name\": \"grpc-web-simple-example\",\n  \"version\": \"0.1.0\",\n  \"description\": \"gRPC-Web simple example\",\n  \"main\": \"server.js\",\n  \"devDependencies\": {\n    \"@grpc/grpc-js\": \"1.13.4\",\n    \"@grpc/proto-loader\": \"~0.5.4\",\n    \"async\": \"~3.2.3\",\n    \"google-protobuf\": \"~3.21.4\",\n    \"grpc-web\": \"~2.0.2\",\n    \"lodash\": \"~4.17.0\",\n    \"webpack\": \"5.101.3\",\n    \"webpack-cli\": \"~5.1.1\"\n  }\n}\n"
  },
  {
    "path": "net/grpc/gateway/examples/helloworld/server.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nvar PROTO_PATH = __dirname + '/helloworld.proto';\n\nvar assert = require('assert');\nvar async = require('async');\nvar _ = require('lodash');\nvar grpc = require('@grpc/grpc-js');\nvar protoLoader = require('@grpc/proto-loader');\nvar packageDefinition = protoLoader.loadSync(\n    PROTO_PATH,\n    {keepCase: true,\n     longs: String,\n     enums: String,\n     defaults: true,\n     oneofs: true\n    });\nvar protoDescriptor = grpc.loadPackageDefinition(packageDefinition);\nvar helloworld = protoDescriptor.helloworld;\n\n/**\n * @param {!Object} call\n * @param {function():?} callback\n */\nfunction doSayHello(call, callback) {\n  callback(null, {message: 'Hello! '+ call.request.name});\n}\n\n/**\n * @param {!Object} call\n */\nfunction doSayRepeatHello(call) {\n  var senders = [];\n  function sender(name) {\n    return (callback) => {\n      call.write({\n        message: 'Hey! ' + name\n      });\n      _.delay(callback, 500); // in ms\n    };\n  }\n  for (var i = 0; i < call.request.count; i++) {\n    senders[i] = sender(call.request.name + i);\n  }\n  async.series(senders, () => {\n    call.end();\n  });\n}\n\n/**\n * @return {!Object} gRPC server\n */\nfunction getServer() {\n  var server = new grpc.Server();\n  server.addService(helloworld.Greeter.service, {\n    sayHello: doSayHello,\n    sayRepeatHello: doSayRepeatHello,\n  });\n  return server;\n}\n\nif (require.main === module) {\n  var server = getServer();\n  server.bindAsync(\n    '0.0.0.0:9090', grpc.ServerCredentials.createInsecure(), (err, port) => {\n      assert.ifError(err);\n      server.start();\n  });\n}\n\nexports.getServer = getServer;\n"
  },
  {
    "path": "packages/grpc-web/.gitignore",
    "content": "/index.js\n/generated/\n\npackage-lock.json\nnode_modules/\n__pycache__/\n"
  },
  {
    "path": "packages/grpc-web/.npmignore",
    "content": "/scripts\n/package-lock.json\n/.gitignore\n"
  },
  {
    "path": "packages/grpc-web/README.md",
    "content": "# gRPC-Web Client Runtime Library\n\ngRPC-Web provides a Javascript library that lets browser clients access a gRPC\nservice. You can find out much more about gRPC in its own\n[website](https://grpc.io).\n\ngRPC-Web is now Generally Available, and considered stable enough for production use.\n\ngRPC-Web clients connect to gRPC services via a special gateway proxy: the\ncurrent version of the library uses [Envoy](https://www.envoyproxy.io/) by\ndefault, in which gRPC-Web support is built-in.\n\nIn the future, we expect gRPC-Web to be supported in language-specific Web\nframeworks, such as Python, Java, and Node. See the\n[roadmap](https://github.com/grpc/grpc-web/blob/master/doc/roadmap.md) doc.\n\n\n## Quick Start\n\nThis example is using the `echo.proto` file from the\n[Echo Example](https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway/examples/echo).\n\n 1. Add `grpc-web` as a dependency using `npm`.\n\n```sh\n$ npm i grpc-web\n```\n\n 2. Download `protoc` and the `protoc-gen-grpc-web` protoc plugin.\n\nYou can download the `protoc` binary from the official\n[protocolbuffers](https://github.com/protocolbuffers/protobuf/releases)\nrelease page.\n\nYou can download the `protoc-gen-grpc-web` protoc plugin from our Github\n[release](https://github.com/grpc/grpc-web/releases) page.\n\n\nMake sure they are both executable and are discoverable from your PATH.\n\n\n 3. Generate your proto messages and the service client stub classes with\n`protoc` and the `protoc-gen-grpc-web` plugin. You can set the\n`import_style=commonjs` option for both `--js_out` and `--grpc-web_out`.\n\n```sh\n$ protoc -I=$DIR echo.proto \\\n--js_out=import_style=commonjs:generated \\\n--grpc-web_out=import_style=commonjs,mode=grpcwebtext:generated\n```\n\n 4. Start using your generated client!\n\n```js\nconst {EchoServiceClient} = require('./generated/echo_grpc_web_pb.js');\nconst {EchoRequest} = require('./generated/echo_pb.js');\n\nconst client = new EchoServiceClient('localhost:8080');\n\nconst request = new EchoRequest();\nrequest.setMessage('Hello World!');\n\nconst metadata = {'custom-header-1': 'value1'};\n\nclient.echo(request, metadata, (err, response) => {\n  // ...\n});\n```\n\n\n## What's Next\n\nTo complete the example, you need to run a proxy that understands the\n[gRPC-Web protocol](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md#protocol-differences-vs-grpc-over-http2)\nbetween your browser client and your gRPC service. The default proxy currently\nis [Envoy](https://www.envoyproxy.io/). Please visit our\n[Github repo](https://github.com/grpc/grpc-web) for more information.\n\nHere's a quick way to get started!\n\n```sh\n$ git clone https://github.com/grpc/grpc-web\n$ cd grpc-web\n$ docker-compose up node-server envoy commonjs-client\n```\n\nOpen a browser tab, and go to:\n\n```\nhttp://localhost:8081/echotest.html\n```\n\n## TypeScript Support\n\nThe `grpc-web` module can now be imported as a TypeScript module. This is\ncurrently an experimental feature. Any feedback welcome!\n\nWhen using the `protoc-gen-grpc-web` protoc plugin, mentioned above, pass in\neither:\n\n - `import_style=commonjs+dts`: existing CommonJS style stub + `.d.ts` typings\n - `import_style=typescript`: full TypeScript output\n\n\n```ts\nimport * as grpcWeb from 'grpc-web';\nimport {EchoServiceClient} from './echo_grpc_web_pb';\nimport {EchoRequest, EchoResponse} from './echo_pb';\n\nconst echoService = new EchoServiceClient('http://localhost:8080', null, null);\n\nconst request = new EchoRequest();\nrequest.setMessage('Hello World!');\n\nconst call = echoService.echo(request, {'custom-header-1': 'value1'},\n  (err: grpcWeb.RpcError, response: EchoResponse) => {\n    console.log(response.getMessage());\n  });\ncall.on('status', (status: grpcWeb.Status) => {\n  // ...\n});\n```\n\nSee a full TypeScript example\n[here](https://github.com/grpc/grpc-web/blob/master/net/grpc/gateway/examples/echo/ts-example/client.ts).\n\n\n## Run Tests\n\nPre-requisites:\n - `protoc`\n - `protoc-gen-grpc-web` plugin\n\n\n```sh\n$ npm test\n```\n"
  },
  {
    "path": "packages/grpc-web/docker/jsunit-test/Dockerfile",
    "content": "FROM selenium/standalone-chrome:112.0.5615.165\n\nARG NODE_VERSION=20.0.0\nUSER root\n\n# Install Node.js dependencies\nRUN apt-get update && apt-get install -y nodejs npm curl\n\n# Install nvm and set up Node.js\nRUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash\nENV NVM_DIR=$HOME/.nvm\nRUN . $NVM_DIR/nvm.sh && \\\n    nvm install $NODE_VERSION && \\\n    nvm alias default $NODE_VERSION && \\\n    nvm use default\nENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH\n\nWORKDIR /grpc-web\n\n# Copy all needed files before running npm install or compiler\nCOPY ./packages ./packages\nCOPY ./javascript ./javascript\nCOPY ./scripts ./scripts\n\n# Install npm dependencies and build the JS library\nWORKDIR /grpc-web/packages/grpc-web\nRUN npm install\n"
  },
  {
    "path": "packages/grpc-web/exports.js",
    "content": "/**\n * @fileoverview Export symbols needed by generated code in CommonJS style.\n *\n * Note that public methods called by generated code are exposed\n * using Closure Compiler's @export annotation\n */\ngoog.module('grpc.web.Exports');\n\nconst CallOptions = goog.require('grpc.web.CallOptions');\nconst MethodDescriptor = goog.require('grpc.web.MethodDescriptor');\nconst GrpcWebClientBase = goog.require('grpc.web.GrpcWebClientBase');\nconst RpcError = goog.require('grpc.web.RpcError');\nconst StatusCode = goog.require('grpc.web.StatusCode');\nconst MethodType = goog.require('grpc.web.MethodType');\n\nmodule['exports']['CallOptions'] = CallOptions;\nmodule['exports']['MethodDescriptor'] = MethodDescriptor;\nmodule['exports']['GrpcWebClientBase'] = GrpcWebClientBase;\nmodule['exports']['RpcError'] = RpcError;\nmodule['exports']['StatusCode'] = StatusCode;\nmodule['exports']['MethodType'] = MethodType;\n\n// Temporary hack to fix https://github.com/grpc/grpc-web/issues/1153, which is\n// caused by `goog.global` not pointing to the global scope when grpc-web is\n// being imported as a CommonJS module.\n// TODO: Remove this hack after `goog.global` is fixed.\ngoog.Timer.defaultTimerObject =  (typeof globalThis !== \"undefined\" && globalThis) || self;\n"
  },
  {
    "path": "packages/grpc-web/externs.js",
    "content": "var module;\n\n/**\n * List of functions we want to preserve when running the closure compiler\n * with --compilation_level=ADVANCED_OPTIMIZATIONS.\n */\nmodule.ClientReadableStream = function() {};\nmodule.ClientReadableStream.prototype.on = function(eventType, callback) {};\nmodule.ClientReadableStream.prototype.removeListener =\n  function(eventType, callback) {};\nmodule.ClientReadableStream.prototype.cancel = function() {};\n\nmodule.GenericClient = function() {};\nmodule.GenericClient.prototype.unaryCall = function(request) {};\nmodule.GenericClient.prototype.call = function(requestMessage,\n                                               methodDescriptor) {};\n\nmodule.UnaryInterceptor = function() {};\nmodule.UnaryInterceptor.prototype.intercept = function(request, invoker) {};\n\nmodule.StreamInterceptor = function() {};\nmodule.StreamInterceptor.prototype.intercept = function(request, invoker) {};\n\nmodule.Request = function() {};\nmodule.Request.prototype.getRequestMessage = function() {};\nmodule.Request.prototype.getMethodDescriptor = function() {};\nmodule.Request.prototype.getMetadata = function() {};\nmodule.Request.prototype.getCallOptions = function() {};\n\nmodule.UnaryResponse = function() {};\nmodule.UnaryResponse.prototype.getResponseMessage = function() {};\nmodule.UnaryResponse.prototype.getMetadata = function() {};\nmodule.UnaryResponse.prototype.getMethodDescriptor = function() {};\nmodule.UnaryResponse.prototype.getStatus = function() {};\n\nmodule.MethodDescriptor = function() {};\nmodule.MethodDescriptor.getName = function() {};\n"
  },
  {
    "path": "packages/grpc-web/gulpfile.js",
    "content": "const connect = require('gulp-connect');\nconst gulp = require('gulp');\n\ngulp.task('serve', () => {\n  connect.server({\n    // Serves the root of github repo so tests an access javascript files.\n    root: '../../',\n    port: 4000\n  });\n});\n"
  },
  {
    "path": "packages/grpc-web/index.d.ts",
    "content": "declare module \"grpc-web\" {\r\n\r\n  export interface Metadata { [s: string]: string; }\r\n\r\n  export class AbstractClientBase {\r\n    thenableCall<REQ, RESP> (\r\n      method: string,\r\n      request: REQ,\r\n      metadata: Metadata,\r\n      methodDescriptor: MethodDescriptor<REQ, RESP>,\r\n      options?: PromiseCallOptions\r\n    ): Promise<RESP>;\r\n  \r\n    unaryCall<REQ, RESP>(\r\n      method: string,\r\n      request: REQ,\r\n      metadata: Metadata,\r\n      methodDescriptor: MethodDescriptor<REQ, RESP> \r\n    ): Promise<RESP>;\r\n\r\n    rpcCall<REQ, RESP> (\r\n      method: string,\r\n      request: REQ,\r\n      metadata: Metadata,\r\n      methodDescriptor: MethodDescriptor<REQ, RESP>,\r\n      callback: (err: RpcError, response: RESP) => void\r\n    ): ClientReadableStream<RESP>;\r\n\r\n    serverStreaming<REQ, RESP> (\r\n      method: string,\r\n      request: REQ,\r\n      metadata: Metadata,\r\n      methodDescriptor: MethodDescriptor<REQ, RESP>\r\n    ): ClientReadableStream<RESP>;\r\n  }\r\n\r\n  export class ClientReadableStream<RESP> {\r\n    on (eventType: \"error\",\r\n        callback: (err: RpcError) => void): ClientReadableStream<RESP>;\r\n    on (eventType: \"status\",\r\n        callback: (status: Status) => void): ClientReadableStream<RESP>;\r\n    on (eventType: \"metadata\",\r\n        callback: (status: Metadata) => void): ClientReadableStream<RESP>;\r\n    on (eventType: \"data\",\r\n        callback: (response: RESP) => void): ClientReadableStream<RESP>;\r\n    on (eventType: \"end\",\r\n        callback: () => void): ClientReadableStream<RESP>;\r\n\r\n    removeListener (eventType: \"error\",\r\n                    callback: (err: RpcError) => void): void;\r\n    removeListener (eventType: \"status\",\r\n                    callback: (status: Status) => void): void;\r\n    removeListener (eventType: \"metadata\",\r\n                    callback: (status: Metadata) => void): void;\r\n    removeListener (eventType: \"data\",\r\n                    callback: (response: RESP) => void): void;\r\n    removeListener (eventType: \"end\",\r\n                    callback: () => void): void;\r\n\r\n    cancel (): void;\r\n  }\r\n\r\n  export interface StreamInterceptor<REQ, RESP> {\r\n    intercept(request: Request<REQ, RESP>,\r\n              invoker: (request: Request<REQ, RESP>) =>\r\n      ClientReadableStream<RESP>): ClientReadableStream<RESP>;\r\n  }\r\n\r\n  export interface UnaryInterceptor<REQ, RESP> {\r\n    intercept(request: Request<REQ, RESP>,\r\n              invoker: (request: Request<REQ, RESP>) =>\r\n      Promise<UnaryResponse<REQ, RESP>>): Promise<UnaryResponse<REQ, RESP>>;\r\n  }\r\n\r\n  /** Options for gRPC-Web calls returning a Promise. */\r\n  export interface PromiseCallOptions {\r\n    /** An AbortSignal to abort the call. */\r\n    readonly signal?: AbortSignal;\r\n  }\r\n\r\n  export class MethodDescriptor<REQ, RESP> {\r\n    constructor(name: string,\r\n                methodType: string,\r\n                requestType: new (...args: unknown[]) => REQ,\r\n                responseType: new (...args: unknown[]) => RESP,\r\n                requestSerializeFn: any,\r\n                responseDeserializeFn: any);\r\n    getName(): string;\r\n  }\r\n\r\n  export class Request<REQ, RESP> {\r\n    getRequestMessage(): REQ;\r\n    getMethodDescriptor(): MethodDescriptor<REQ, RESP>;\r\n    getMetadata(): Metadata;\r\n  }\r\n\r\n  export class UnaryResponse<REQ, RESP> {\r\n    getResponseMessage(): RESP;\r\n    getMetadata(): Metadata;\r\n    getMethodDescriptor(): MethodDescriptor<REQ, RESP>;\r\n    getStatus(): Status;\r\n  }\r\n\r\n  export interface GrpcWebClientBaseOptions {\r\n    format?: string;\r\n    suppressCorsPreflight?: boolean;\r\n    withCredentials?: boolean;\r\n    unaryInterceptors?: UnaryInterceptor<unknown, unknown>[];\r\n    streamInterceptors?: StreamInterceptor<unknown, unknown>[];\r\n  }\r\n\r\n  export class GrpcWebClientBase extends AbstractClientBase {\r\n    constructor(options?: GrpcWebClientBaseOptions);\r\n  }\r\n\r\n  export class RpcError extends Error {\r\n    constructor(code: StatusCode, message: string, metadata: Metadata);\r\n    code: StatusCode;\r\n    metadata: Metadata;\r\n  }\r\n\r\n  export interface Status {\r\n    code: number;\r\n    details: string;\r\n    metadata?: Metadata;\r\n  }\r\n\r\n  export enum StatusCode {\r\n    OK,\r\n    CANCELLED,\r\n    UNKNOWN,\r\n    INVALID_ARGUMENT,\r\n    DEADLINE_EXCEEDED,\r\n    NOT_FOUND,\r\n    ALREADY_EXISTS,\r\n    PERMISSION_DENIED,\r\n    RESOURCE_EXHAUSTED,\r\n    FAILED_PRECONDITION,\r\n    ABORTED,\r\n    OUT_OF_RANGE,\r\n    UNIMPLEMENTED,\r\n    INTERNAL,\r\n    UNAVAILABLE,\r\n    DATA_LOSS,\r\n    UNAUTHENTICATED,\r\n  }\r\n\r\n  export namespace MethodType {\r\n    const UNARY: string;\r\n    const SERVER_STREAMING: string;\r\n  }\r\n}\r\n"
  },
  {
    "path": "packages/grpc-web/package.json",
    "content": "{\n  \"name\": \"grpc-web\",\n  \"version\": \"2.0.2\",\n  \"author\": \"Google Inc.\",\n  \"description\": \"gRPC-Web Client Runtime Library\",\n  \"homepage\": \"https://grpc.io/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/grpc/grpc-web.git\"\n  },\n  \"bugs\": \"https://github.com/grpc/grpc-web/issues\",\n  \"files\": [\n    \"index.js\",\n    \"index.d.ts\"\n  ],\n  \"main\": \"index.js\",\n  \"typings\": \"index.d.ts\",\n  \"scripts\": {\n    \"build\": \"node scripts/build.js\",\n    \"prepare\": \"npm run build\",\n    \"prepublishOnly\": \"npm run build\",\n    \"test\": \"npm run test-jsunit && npm run test-mocha\",\n    \"test-mocha\": \"mocha --timeout 10000 \\\"./test/**/*_test.js\\\"\",\n    \"test-jsunit\": \"./scripts/generate_test_files.sh && ./scripts/run_jsunit_tests.sh && rm -rf ./generated\"\n  },\n  \"license\": \"Apache-2.0\",\n  \"devDependencies\": {\n    \"@types/google-protobuf\": \"~3.15.12\",\n    \"command-exists\": \"~1.2.8\",\n    \"google-closure-compiler\": \"^20250820.0.0\",\n    \"google-closure-deps\": \"~20210601.0.0\",\n    \"google-closure-library\": \"^20230802.0.0\",\n    \"google-protobuf\": \"~3.21.4\",\n    \"gulp\": \"~4.0.2\",\n    \"gulp-connect\": \"~5.7.0\",\n    \"gulp-eval\": \"~1.0.0\",\n    \"mocha\": \"~5.2.0\",\n    \"mock-xmlhttprequest\": \"~2.0.0\",\n    \"protractor\": \"~7.0.0\",\n    \"typescript\": \"latest\"\n  }\n}\n"
  },
  {
    "path": "packages/grpc-web/protractor.conf.js",
    "content": "/**\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Stores the configuration of Protractor. It is loaded by protractor to run\n * tests.\n *\n * Intended to be used through ./run_jsunit_test.sh\n */\n\n// Common configuration.\nconfig = {\n  // Using jasmine to wrap Closure JSUnit tests.\n  framework: 'jasmine',\n  // The jasmine specs to run.\n  specs: ['protractor_spec.js'],\n  // Jasmine options. Increase the timeout to 5min instead of the default 30s.\n  jasmineNodeOpts: {\n    // Default time to wait in ms before a test fails.\n    defaultTimeoutInterval: 5 * 60 * 1000 // 5 minutes\n  }\n};\n\n// Configuration for headless chrome.\nconfig.directConnect = true;\nconfig.multiCapabilities = [{\n  browserName: 'chrome',\n  chromeOptions: {\n    args: [ \"--headless\", \"--disable-gpu\", \"--window-size=800,600\",\n            \"--no-sandbox\", \"--disable-dev-shm-usage\" ]\n  }\n}];\n\nexports.config = config;\n"
  },
  {
    "path": "packages/grpc-web/protractor_spec.js",
    "content": "/**\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nvar allTests = require('./generated/all_tests');\n\nvar TEST_SERVER = 'http://localhost:4000';\n\ndescribe('Run all Closure unit tests', function() {\n  /**\n   * Waits for current tests to be executed.\n   * @param {function(!Object)} done The function called when the test is finished.\n   * @param {function(!Error)} fail The function called when an unrecoverable error\n   *     happened during the test.\n   */\n  var waitForTest = function(done, fail) {\n    // executeScript runs the passed method in the \"window\" context of\n    // the current test. JSUnit exposes hooks into the test's status through\n    // the \"G_testRunner\" global object.\n    browser.executeScript(function() {\n      if (window['G_testRunner'] && window['G_testRunner']['isFinished']()) {\n        return {\n          isFinished: true,\n          isSuccess: window['G_testRunner']['isSuccess'](),\n          report: window['G_testRunner']['getReport']()\n        };\n      } else {\n        return {'isFinished': false};\n      }\n    }).then(function(status) {\n      if (status && status.isFinished) {\n        done(status);\n      } else {\n        waitForTest(done, fail);\n      }\n    }, function(err) {\n      // This can happen if the webdriver had an issue executing the script.\n      fail(err);\n    });\n  };\n\n  /**\n   * Executes the test cases for the file at the given testPath.\n   * @param {!string} testPath The path of the current test suite to execute.\n   */\n  var executeTest = function(testPath) {\n    it('runs ' + testPath + ' with success', function(done) {\n      /**\n       * Runs the test routines for a given test path.\n       * @param {function()} done The function to run on completion.\n       */\n      var runRoutine = function(done) {\n        browser.navigate()\n            .to(TEST_SERVER + '/' + testPath)\n            .then(function() {\n              waitForTest(function(status) {\n                expect(status).toBeSuccess();\n                done();\n              }, function(err) {\n                done.fail(err);\n              });\n            }, function(err) {\n              done.fail(err);\n            });\n      };\n      // Run the test routine.\n      runRoutine(done);\n    });\n  };\n\n  beforeEach(function() {\n    jasmine.addMatchers({\n      // This custom matcher allows for cleaner reports.\n      toBeSuccess: function() {\n        return {\n          // Checks that the status report is successful, otherwise displays\n          // the report as error message.\n          compare: function(status) {\n            return {\n              pass: status.isSuccess,\n              message: 'Some test cases failed!\\n\\n' + status.report\n            };\n          }\n        };\n      }\n    });\n  });\n\n  if (!allTests.length) {\n    throw new Error('Cannot find any JsUnit tests!!');\n  }\n\n  // Run all tests.\n  for (var i = 0; i < allTests.length; i++) {\n    var testPath = allTests[i];\n    executeTest(testPath);\n  }\n});\n"
  },
  {
    "path": "packages/grpc-web/scripts/build.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nconst fs = require(\"fs\");\nconst path = require(\"path\");\nconst {exec} = require(\"child_process\");\n\nconst cwd = process.cwd();\n\nconst indexPath = path.relative(cwd, path.resolve(__dirname, \"../index.js\"));\n\nconst jsPaths = [\n  \"../exports.js\",\n  \"../../../javascript\",\n  \"../node_modules/google-closure-library\",\n].map(jsPath => path.relative(cwd, path.resolve(__dirname, jsPath)));\n\nconst closureArgs = [].concat(\n  jsPaths.map(jsPath => `--js=${jsPath}`),\n  [\n    `--entry_point=grpc.web.Exports`,\n    `--externs=externs.js`,\n    `--dependency_mode=PRUNE`,\n    `--compilation_level=ADVANCED_OPTIMIZATIONS`,\n    `--generate_exports`,\n    `--export_local_property_definitions`,\n    `--js_output_file=${indexPath}`,\n  ]\n);\n\nconst closureCompilerBin =\n  path.resolve(__dirname, \"../node_modules/.bin/google-closure-compiler\");\nconst closureCommand = closureCompilerBin + \" \" + closureArgs.join(' ');\n\nconsole.log(closureCommand);\nlet child = exec(closureCommand);\n\nchild.stdout.pipe(process.stdout);\nchild.stderr.pipe(process.stderr);\n\nfunction createSymlink(target, path) {\n  fs.symlink(target, path, (err) => {\n    if (err && err.code != 'EEXIST') {\n      throw err;\n    }\n  });\n}\n\ncreateSymlink(path.resolve(__dirname, \"../index.js\"),\n              path.resolve(__dirname, \"../node_modules/grpc-web.js\"));\ncreateSymlink(path.resolve(__dirname, \"../index.d.ts\"),\n              path.resolve(__dirname, \"../node_modules/grpc-web.d.ts\"));"
  },
  {
    "path": "packages/grpc-web/scripts/common.py",
    "content": "# Copyright 2021 Google Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Common methods and constants for generating test files.\"\"\"\n\nimport os\nfrom typing import Iterator\n\n# The directory in which test HTML files are generated.\nGENERATED_TEST_BASE_PATH = \"generated/test_htmls/\"\n\n\ndef read_file(path: str) -> str:\n    \"\"\"Reads the content of a file.\"\"\"\n    with open(path) as f:\n        return f.read()\n\n\ndef write_file(path: str, content: str):\n    \"\"\"Writes a string to file, overwriting existing content; intermediate\n    directories are created if not present.\"\"\"\n    dir_name = os.path.dirname(path)\n    if not os.path.exists(dir_name):\n        os.makedirs(dir_name)\n\n    with open(path, \"w\") as f:\n        f.write(content)\n\n\ndef get_files_with_suffix(root_dir: str, suffix: str) -> Iterator[str]:\n    \"\"\"Yields file names under a directory with a given suffix.\"\"\"\n    for dir_path, _, file_names in os.walk(root_dir):\n        for file_name in file_names:\n            if file_name.endswith(suffix):\n                yield os.path.join(dir_path, file_name)\n"
  },
  {
    "path": "packages/grpc-web/scripts/gen_all_tests_js.py",
    "content": "# Copyright 2021 Google Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Generates the all_tests.js file for consumption by Protractor.\n\nUsage:\n$ cd packages/grpc-web\n$ python3 ./scripts/gen_test_htmls.py # Prerequisite\n$ python3 ./scripts/gen_all_tests_js.py\n\"\"\"\n\nfrom string import Template\n\nimport common\n\nALL_TESTS_TEMPLATE_FILE = './scripts/template_all_tests_js.txt'\n\n# The path of the generated all_tests.js file\nGENERATED_ALL_TESTS_JS_PATH = './generated/all_tests.js'\n\n# File paths needs to be prepended by the relative path of the grpc-web package\n# because web server is hosting the root of github repo for tests to access the\n# javascript files.\nGRPC_WEB_BASE_DIR = 'packages/grpc-web'\n\n\ndef main():\n    template_data = common.read_file(ALL_TESTS_TEMPLATE_FILE)\n    template = Template(template_data)\n\n    test_html_paths = []\n    for file_name in common.get_files_with_suffix(\n            common.GENERATED_TEST_BASE_PATH, '_test.html'):\n        test_html_paths.append(\"  '%s/%s',\" % (GRPC_WEB_BASE_DIR, file_name))\n    # Example output paths:\n    # 'packages/grpc-web/generated/test_htmls/javascript__net__grpc__web__grpcwebclientbase_test.html',\n    # 'packages/grpc-web/generated/test_htmls/javascript__net__grpc__web__grpcwebstreamparser_test.html',\n    test_html_paths_str = \"\\n\".join(test_html_paths)\n\n    # Writes the generated output to the all_tests.js file.\n    common.write_file(GENERATED_ALL_TESTS_JS_PATH,\n                      template.substitute(test_html_paths=test_html_paths_str))\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "packages/grpc-web/scripts/gen_test_htmls.py",
    "content": "# Copyright 2021 Google Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Generates *_test.html files from *_test.js files.\n\nUsage:\n$ cd packages/grpc-web\n$ python3 ./scripts/gen_test_htmls.py\n\"\"\"\n\nimport os\nimport re\nfrom string import Template\n\nimport common\n\n# The directories containing JS tests.\nDIRECTORIES_WITH_TESTS = [\"../../javascript\"]\n\nTEST_HTML_TEMPLATE_FILE = './scripts/template_test_html.txt'\n\n\ndef main():\n    template_data = common.read_file(TEST_HTML_TEMPLATE_FILE)\n    template = Template(template_data)\n    for directory in DIRECTORIES_WITH_TESTS:\n        for js_file_path in common.get_files_with_suffix(\n                directory, \"_test.js\"):\n            _gen_test_html(js_file_path, template)\n\n\ndef _gen_test_html(js_file_path: str, template: Template):\n    \"\"\"Generates a Closure test wrapper HTML and saves it to the filesystem.\"\"\"\n    # Generates the test_file_name so that:\n    #   ../../javascript/net/grpc/web/grpcwebclientbase_test.js\n    # will now be named:\n    #   javascript__net__grpc__web__grpcwebclientbase_test.html\n    test_file_name = js_file_path\n    while test_file_name.startswith('../'):\n        test_file_name = test_file_name[3:]\n    test_file_name = test_file_name.replace('/', '__')\n    test_file_name = os.path.splitext(test_file_name)[0] + '.html'\n\n    # Generates the test HTML using the package name of the test file\n    package_name = _extract_closure_package(js_file_path)\n    generated_html = template.substitute(package=package_name)\n\n    # Writes the test HTML files\n    common.write_file(common.GENERATED_TEST_BASE_PATH + test_file_name,\n                      generated_html)\n\n\ndef _extract_closure_package(js_file_path) -> str:\n    \"\"\"Extracts the package name from goog.provide() or goog.module() in the\n    JS file.\"\"\"\n    js_data = common.read_file(js_file_path)\n    matches = re.search(r\"goog\\.(provide|module)\\([\\n\\s]*'(.+)'\\);\", js_data)\n\n    if matches is None:\n        raise ValueError(\"goog.provide() or goog.module() not found in file\")\n\n    return matches.group(2)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "packages/grpc-web/scripts/generate_test_files.sh",
    "content": "#!/bin/bash\n# Copyright 2021 Google Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Generates the temporary files needed for tests to run, putting them in the\n# generated/ directory.\n#\n# Usage:\n# $ cd packages/grpc-web\n# $ ./scripts/generate_test_files.sh\n\nset -ex\n\nSCRIPT_DIR=$(dirname \"$0\")\nREPO_DIR=$(realpath \"${SCRIPT_DIR}/../\")\nJAVASCRIPT_DIR=$(realpath \"${SCRIPT_DIR}/../../../javascript\")\nGEN_DIR=\"$REPO_DIR/generated\"\n\ncd \"$REPO_DIR\"\n\nmkdir -p \"$GEN_DIR\"\n\necho \"Generating dependency file...\"\nnpx closure-make-deps \\\n    --closure-path=\"node_modules/google-closure-library/closure/goog\" \\\n    --file=\"node_modules/google-closure-library/closure/goog/deps.js\" \\\n    --root=\"$JAVASCRIPT_DIR\" \\\n    --exclude=\"$GEN_DIR/all_tests.js\" \\\n    --exclude=\"$GEN_DIR/deps.js\" \\\n    > \"$GEN_DIR/deps.js\"\n\necho \"Generating test HTML files...\"\npython3 ./scripts/gen_test_htmls.py\npython3 ./scripts/gen_all_tests_js.py\n\necho \"Done.\"\n"
  },
  {
    "path": "packages/grpc-web/scripts/run_jsunit_tests.sh",
    "content": "#!/bin/bash\n# Copyright 2021 Google Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# This script starts a local HTTP server to serve test files, starts a Selenium Webdriver, and\n# runs the unit tests using Protractor.\n# Run locally with Pratractor:\n#\n# Usage (under ./packages/grpc-web):\n# $ ./scripts/generate_test_files.sh # Required first step\n# $ ./scripts/run_jsunit_tests.sh\n#\n# Or (preferred use):\n# $ npm run test-jsunit\n\nset -e\n\ncd \"$(dirname $(dirname \"$0\"))\"\nPROTRACTOR_BIN_PATH=\"./node_modules/protractor/bin\"\n\nfunction cleanup () {\n  echo \"Killing HTTP Server...\"\n  kill $serverPid\n}\n\n# Start the local webserver.\necho \"Starting local HTP Server...\"\nnpx gulp serve &\nserverPid=$!\necho \"Local HTTP Server started with PID $serverPid.\"\n\ntrap cleanup EXIT\n\necho \"Using Headless Chrome.\"\n# Updates Selenium Webdriver.\necho \"$PROTRACTOR_BIN_PATH/webdriver-manager update --versions.chrome=112.0.5615.165 --gecko=false\"\n$PROTRACTOR_BIN_PATH/webdriver-manager update --versions.chrome=112.0.5615.165 --gecko=false\n\n# Run the tests using Protractor! (Protractor should run selenium automatically)\n$PROTRACTOR_BIN_PATH/protractor protractor.conf.js\n"
  },
  {
    "path": "packages/grpc-web/scripts/template_all_tests_js.txt",
    "content": "var allTests = [\n$test_html_paths\n];\nif (typeof module !== 'undefined' && module.exports) {\n  module.exports = allTests;\n}\n"
  },
  {
    "path": "packages/grpc-web/scripts/template_test_html.txt",
    "content": "<!-- Copyright (c) 2021 Google Inc. All rights reserved. -->\n<!doctype html>\n<html>\n<head>\n  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n  <meta charset=\"UTF-8\" />\n  <script src=\"../../node_modules/google-closure-library/closure/goog/base.js\"></script>\n  <script src=\"../deps.js\"></script>\n  <script>\n    goog.require('$package');\n  </script>\n</head>\n<body>\n</body>\n</html>\n"
  },
  {
    "path": "packages/grpc-web/test/closure_client.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\ngoog.provide('proto.grpc.gateway.testing.EchoAppClient');\n\ngoog.require('proto.grpc.gateway.testing.EchoServiceClient');\ngoog.require('proto.grpc.gateway.testing.EchoRequest');\n\n\nproto.grpc.gateway.testing.EchoAppClient = function() {\n  this.client =\n    new proto.grpc.gateway.testing.EchoServiceClient('MyHostname', null, null);\n}\n\nproto.grpc.gateway.testing.EchoAppClient.prototype.echo = function(msg, cb) {\n  var request = new proto.grpc.gateway.testing.EchoRequest();\n  request.setMessage(msg);\n  this.client.echo(request, {}, cb);\n}\n"
  },
  {
    "path": "packages/grpc-web/test/common.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nconst fs = require('fs');\nconst GENERATED_CODE_PATH = './generated';\n\nvar removeDirectory = function(path) {\n  if (fs.existsSync(path)) {\n    fs.readdirSync(path).forEach(function(file, index) {\n      var curPath = path + \"/\" + file;\n      if (fs.lstatSync(curPath).isDirectory()) {\n        removeDirectory(curPath);\n      } else {\n        fs.unlinkSync(curPath);\n      }\n    });\n    fs.rmdirSync(path);\n  }\n}\n\nexports.removeDirectory = removeDirectory;\nexports.GENERATED_CODE_PATH = GENERATED_CODE_PATH;\n"
  },
  {
    "path": "packages/grpc-web/test/eval_test.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nconst assert = require('assert');\nconst execSync = require('child_process').execSync;\nconst commandExists = require('command-exists').sync;\nconst fs = require('fs');\nconst path = require('path');\nconst removeDirectory = require('./common.js').removeDirectory;\nconst GENERATED_CODE_PATH = require('./common.js').GENERATED_CODE_PATH;\n\ndescribe('grpc-web generated code eval test (commonjs+dts)', function() {\n  const genCodeCmd =\n    'protoc -I=./test/protos foo.proto models.proto ' +\n    '--js_out=import_style=commonjs:./test/generated ' +\n    '--grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:' +\n    './test/generated';\n\n  before(function() {\n    ['protoc', 'protoc-gen-grpc-web'].map(prog => {\n      if (!commandExists(prog)) {\n        assert.fail(`${prog} is not installed`);\n      }\n    });\n  });\n\n  beforeEach(function() {\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n    fs.mkdirSync(path.resolve(__dirname, GENERATED_CODE_PATH));\n  });\n\n  afterEach(function() {\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n  });\n\n  it('should eval', function() {\n    execSync(genCodeCmd);\n    execSync(`npx gulp --gulpfile ./test/gulpfile.js gen-code-eval-test`);\n  })\n});\n\n\ndescribe('grpc-web generated code eval test (typescript)', function() {\n  const genTsCodePath = path.resolve(__dirname,\n                                     './generated/FooServiceClientPb.ts');\n\n  const genCodeCmd =\n    'protoc -I=./test/protos foo.proto models.proto ' +\n    '--js_out=import_style=commonjs:./test/generated ' +\n    '--grpc-web_out=import_style=typescript,mode=grpcwebtext:./test/generated';\n\n  before(function() {\n    ['protoc', 'protoc-gen-grpc-web'].map(prog => {\n      if (!commandExists(prog)) {\n        assert.fail(`${prog} is not installed`);\n      }\n    });\n  });\n\n  beforeEach(function() {\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n    fs.mkdirSync(path.resolve(__dirname, GENERATED_CODE_PATH));\n  });\n\n  afterEach(function() {\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n  });\n\n  it('should eval', function() {\n    execSync(genCodeCmd);\n    // --skipLibCheck is needed because some of our node_modules/ targets es6\n    // but our test doesn't pass with `--target es6`\n    // TODO: Find out how we can enable --target es6!\n    execSync(`tsc --strict --skipLibCheck ${genTsCodePath}`);\n  });\n});\n"
  },
  {
    "path": "packages/grpc-web/test/export_test.js",
    "content": "const assert = require('assert');\nconst grpc = {};\ngrpc.web = require('grpc-web');\n\ndescribe('grpc-web export test', function() {\n  it('should have MethodDescriptor exported', function() {\n    assert.equal(typeof grpc.web.MethodDescriptor, 'function');\n  });\n\n  it('should have GrpcWebClientBase#rpcCall() exported', function() {\n    assert.equal(typeof grpc.web.GrpcWebClientBase.prototype.rpcCall, 'function');\n  });\n\n  it('should have GrpcWebClientBase#serverStreaming() exported', function() {\n    assert.equal(typeof grpc.web.GrpcWebClientBase.prototype.serverStreaming, 'function');\n  });\n\n  it('should have RpcError properties exported', function() {\n    const rpcError = new grpc.web.RpcError(/* code= */ 0, 'message');\n    assert.equal(typeof rpcError.code, 'number');\n    assert.equal(typeof rpcError.message, 'string');\n    assert.equal(typeof rpcError.metadata, 'object');\n  });\n\n  it('should have StatusCode exported', function() {\n    assert.deepEqual(grpc.web.StatusCode, {\n      ABORTED: 10,\n      ALREADY_EXISTS: 6,\n      CANCELLED: 1,\n      DATA_LOSS: 15,\n      DEADLINE_EXCEEDED: 4,\n      FAILED_PRECONDITION: 9,\n      INTERNAL: 13,\n      INVALID_ARGUMENT: 3,\n      NOT_FOUND: 5,\n      OK: 0,\n      OUT_OF_RANGE: 11,\n      PERMISSION_DENIED: 7,\n      RESOURCE_EXHAUSTED: 8,\n      UNAUTHENTICATED: 16,\n      UNAVAILABLE: 14,\n      UNIMPLEMENTED: 12,\n      UNKNOWN: 2\n    });\n  });\n});\n"
  },
  {
    "path": "packages/grpc-web/test/generated_code_test.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nconst assert = require('assert');\nconst execSync = require('child_process').execSync;\nconst commandExists = require('command-exists').sync;\nconst fs = require('fs');\nconst path = require('path');\nconst removeDirectory = require('./common.js').removeDirectory;\nconst GENERATED_CODE_PATH = require('./common.js').GENERATED_CODE_PATH;\nconst mockXmlHttpRequest = require('mock-xmlhttprequest');\n\nvar MockXMLHttpRequest;\n\nfunction multiDone(done, count) {\n  return function() {\n    count -= 1;\n    if (count <= 0) {\n      done();\n    }\n  };\n}\n\ndescribe('protoc generated code', function() {\n  const genCodePath = path.resolve(__dirname, './echo_pb.js');\n  const genCodeCmd = 'protoc -I=./test/protos echo.proto ' +\n                     '--js_out=import_style=commonjs:./test';\n\n  before(function() {\n    if (!commandExists('protoc')) {\n      assert.fail('protoc is not installed');\n    }\n  });\n\n  beforeEach(function() {\n    if (fs.existsSync(genCodePath)) {\n      fs.unlinkSync(genCodePath);\n    }\n  });\n\n  afterEach(function() {\n    if (fs.existsSync(genCodePath)) {\n      fs.unlinkSync(genCodePath);\n    }\n  });\n\n  it('should exist', function() {\n    execSync(genCodeCmd);\n    assert.equal(true, fs.existsSync(genCodePath));\n  });\n\n  it('should import', function() {\n    execSync(genCodeCmd);\n    const {EchoRequest} = require(genCodePath);\n    var req = new EchoRequest();\n    req.setMessage('abc');\n    assert.equal('abc', req.getMessage());\n  });\n});\n\ndescribe('grpc-web generated code: promise-based client', function() {\n  const protoGenCodePath = path.resolve(__dirname, './echo_pb.js');\n  const genCodePath = path.resolve(__dirname, './echo_grpc_web_pb.js');\n\n  const genCodeCmd =\n    'protoc -I=./test/protos echo.proto ' +\n    '--js_out=import_style=commonjs:./test ' +\n    '--grpc-web_out=import_style=commonjs,mode=grpcwebtext:./test';\n\n  before(function() {\n    MockXMLHttpRequest = mockXmlHttpRequest.newMockXhr()\n    global.XMLHttpRequest = MockXMLHttpRequest;\n\n    execSync(genCodeCmd);\n    assert.equal(true, fs.existsSync(protoGenCodePath));\n    assert.equal(true, fs.existsSync(genCodePath));\n  });\n\n  after(function() {\n    fs.unlinkSync(protoGenCodePath);\n    fs.unlinkSync(genCodePath);\n  });\n\n  it('should receive unary response', function(done) {\n    const {EchoServicePromiseClient} = require(genCodePath);\n    const {EchoRequest} = require(protoGenCodePath);\n    var echoService = new EchoServicePromiseClient('MyHostname', null, null);\n    var request = new EchoRequest();\n    request.setMessage('aaa');\n\n    MockXMLHttpRequest.onSend = function(xhr) {\n      // a single data frame with message 'aaa'\n      assert.equal(\"AAAAAAUKA2FhYQ==\", xhr.body);\n      xhr.respond(\n        200, {'Content-Type': 'application/grpc-web-text'},\n        // a single data frame with message 'aaa'\n        'AAAAAAUKA2FhYQ==');\n    };\n    echoService.echo(request, {})\n               .then((response) => {\n                 assert.equal('aaa', response.getMessage());\n                 done();\n               });\n  });\n\n  it('should receive error', function(done) {\n    const {EchoServicePromiseClient} = require(genCodePath);\n    const {EchoRequest} = require(protoGenCodePath);\n    var echoService = new EchoServicePromiseClient('MyHostname', null, null);\n    var request = new EchoRequest();\n    request.setMessage('aaa');\n\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        400, {'Content-Type': 'application/grpc-web-text'});\n    };\n    echoService.echo(request, {})\n               .then((response) => {\n                 assert.fail('should not receive response');\n               })\n               .catch((error) => {\n                 assert.equal(3, error.code);\n                 done();\n               });\n  });\n});\n\ndescribe('grpc-web generated code (commonjs+grpcwebtext)', function() {\n  const oldXMLHttpRequest = global.XMLHttpRequest;\n\n  const protoGenCodePath = path.resolve(__dirname, './echo_pb.js');\n  const genCodePath = path.resolve(__dirname, './echo_grpc_web_pb.js');\n\n  const genCodeCmd =\n    'protoc -I=./test/protos echo.proto ' +\n    '--js_out=import_style=commonjs:./test ' +\n    '--grpc-web_out=import_style=commonjs,mode=grpcwebtext:./test';\n\n  before(function() {\n    ['protoc', 'protoc-gen-grpc-web'].map(prog => {\n      if (!commandExists(prog)) {\n        assert.fail(`${prog} is not installed`);\n      }\n    });\n  });\n\n  beforeEach(function() {\n    if (fs.existsSync(protoGenCodePath)) {\n      fs.unlinkSync(protoGenCodePath);\n    }\n    if (fs.existsSync(genCodePath)) {\n      fs.unlinkSync(genCodePath);\n    }\n    MockXMLHttpRequest = mockXmlHttpRequest.newMockXhr()\n    global.XMLHttpRequest = MockXMLHttpRequest;\n  });\n\n  afterEach(function() {\n    if (fs.existsSync(protoGenCodePath)) {\n      fs.unlinkSync(protoGenCodePath);\n    }\n    if (fs.existsSync(genCodePath)) {\n      fs.unlinkSync(genCodePath);\n    }\n    global.XMLHttpRequest = oldXMLHttpRequest;\n  });\n\n  it('should exist', function() {\n    execSync(genCodeCmd);\n    assert.equal(true, fs.existsSync(genCodePath));\n  });\n\n  it('should import', function() {\n    execSync(genCodeCmd);\n    const {EchoServiceClient} = require(genCodePath);\n    var echoService = new EchoServiceClient('Bla', null, null);\n    assert.equal('function', typeof echoService.echo);\n  });\n\n  it('should send unary request', function(done) {\n    execSync(genCodeCmd);\n    const {EchoServiceClient} = require(genCodePath);\n    const {EchoRequest} = require(protoGenCodePath);\n    var echoService = new EchoServiceClient('MyHostname', null, null);\n    var request = new EchoRequest();\n    request.setMessage('aaa');\n    MockXMLHttpRequest.onSend = function(xhr) {\n      assert.equal('POST', xhr.method);\n      // a single 'aaa' string, encoded\n      assert.equal('AAAAAAUKA2FhYQ==', xhr.body);\n      assert.equal('MyHostname/grpc.gateway.testing.EchoService/Echo',\n                   xhr.url);\n      assert.equal(\n        'accept: application/grpc-web-text\\r\\n' +\n        'content-type: application/grpc-web-text\\r\\n' +\n        'custom-header-1: value1\\r\\n' +\n        'x-grpc-web: 1\\r\\n' +\n        'x-user-agent: grpc-web-javascript/0.1\\r\\n',\n        xhr.requestHeaders.getAll());\n      done();\n    };\n    echoService.echo(request, {'custom-header-1':'value1'});\n  });\n\n  it('should receive unary response', function(done) {\n    execSync(genCodeCmd);\n    const {EchoServiceClient} = require(genCodePath);\n    const {EchoRequest} = require(protoGenCodePath);\n    var echoService = new EchoServiceClient('MyHostname', null, null);\n    var request = new EchoRequest();\n    request.setMessage('aaa');\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(200, {'Content-Type': 'application/grpc-web-text'},\n                  // a single data frame with 'aaa' message, encoded\n                  'AAAAAAUKA2FhYQ==');\n    };\n    var call = echoService.echo(request, {'custom-header-1':'value1'},\n                                function(err, response) {\n                                  assert.equal('aaa', response.getMessage());\n                                  done();\n    });\n    call.on('data', (response) => {\n      assert.fail('should not receive response this way');\n    });\n  });\n\n  it('should receive streaming response', function(done) {\n    done = multiDone(done, 4); // done() should be called 4 times\n    execSync(genCodeCmd);\n    const {EchoServiceClient} = require(genCodePath);\n    const {ServerStreamingEchoRequest} = require(protoGenCodePath);\n    var echoService = new EchoServiceClient('MyHostname', null, null);\n    var request = new ServerStreamingEchoRequest();\n    request.setMessage('aaa');\n    request.setMessageCount(3);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      // a proto message of 1: \"aaa\", 2: 3, base64-encoded\n      assert.equal(\"AAAAAAcKA2FhYRAD\", xhr.body);\n      xhr.respond(200, {'Content-Type': 'application/grpc-web-text'},\n                  // 3 'aaa' messages in 3 data frames, encoded\n                  'AAAAAAUKA2FhYQAAAAAFCgNhYWEAAAAABQoDYWFh');\n    };\n    var stream = echoService.serverStreamingEcho(request, {});\n    stream.on('data', function(response) {\n      assert.equal('aaa', response.getMessage());\n      done();\n    });\n    stream.on('end', function() {\n      done();\n    });\n  });\n\n  it('should receive trailing metadata', function(done) {\n    done = multiDone(done, 2);\n    execSync(genCodeCmd);\n    const {EchoServiceClient} = require(genCodePath);\n    const {EchoRequest} = require(protoGenCodePath);\n    var echoService = new EchoServiceClient('MyHostname', null, null);\n    var request = new EchoRequest();\n    request.setMessage('aaa');\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        200, {'Content-Type': 'application/grpc-web-text'},\n        // a single data frame with an 'aaa' message, followed by,\n        // a trailer frame with content 'grpc-status: 0\\d\\ax-custom-1: ababab'\n        'AAAAAAUKA2FhYYAAAAAkZ3JwYy1zdGF0dXM6IDANCngtY3VzdG9tLTE6IGFiYWJhYg0K'\n      );\n    };\n    var call = echoService.echo(\n      request, {'custom-header-1':'value1'},\n      function(err, response) {\n        if (err) {\n          assert.fail('should not receive error');\n        }\n        assert(response);\n        assert.equal('aaa', response.getMessage());\n        done();\n    });\n    call.on('status', function(status) {\n      assert.equal(0, status.code);\n      assert.equal('object', typeof status.metadata);\n      assert.equal(false, 'grpc-status' in status.metadata);\n      assert.equal(true, 'x-custom-1' in status.metadata);\n      assert.equal('ababab', status.metadata['x-custom-1']);\n      done();\n    });\n  });\n\n  it('should receive error', function(done) {\n    execSync(genCodeCmd);\n    const {EchoServiceClient} = require(genCodePath);\n    const {EchoRequest} = require(protoGenCodePath);\n    var echoService = new EchoServiceClient('MyHostname', null, null);\n    var request = new EchoRequest();\n    request.setMessage('aaa');\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(200, {'Content-Type': 'application/grpc-web-text'},\n                  // a trailer frame with content 'grpc-status:10'\n                  'gAAAABBncnBjLXN0YXR1czoxMA0K');\n    };\n    var call = echoService.echo(\n      request, {'custom-header-1':'value1'},\n      function(err, response) {\n        if (response) {\n          assert.fail('should not have received response');\n        }\n        assert(err);\n        assert.equal(10, err.code);\n        done();\n    });\n    call.on('error', (error) => {\n      assert.fail('error callback should not be called for unary calls');\n    });\n  });\n\n  it('should error out on incomplete response', function(done) {\n    execSync(genCodeCmd);\n    const {EchoServiceClient} = require(genCodePath);\n    const {EchoRequest} = require(protoGenCodePath);\n    var echoService = new EchoServiceClient('MyHostname', null, null);\n    var request = new EchoRequest();\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(200, {'Content-Type': 'application/grpc-web-text'},\n                  // An incomplete response. The frame length indicates\n                  // 26 bytes, but the rest of the frame only contains\n                  // 18 bytes.\n                  'AAAAABoKCwgBEgdGaWN0aW9uCgsIAhI');\n    };\n    var call = echoService.echo(\n      request, {}, function(err, response) {\n        if (response) {\n          assert.fail('should not receive response');\n        }\n        assert.equal(2, err.code);\n        assert.equal(true, err.message.toLowerCase().includes(\n          'incomplete response'));\n        done();\n    });\n    call.on('data', (response) => {\n      assert.fail('should not receive response this way');\n    });\n    call.on('error', (error) => {\n      assert.fail('should not receive error this way');\n    });\n  });\n\n  it('should error out on invalid proto response', function(done) {\n    execSync(genCodeCmd);\n    const {EchoServiceClient} = require(genCodePath);\n    const {EchoRequest} = require(protoGenCodePath);\n    var echoService = new EchoServiceClient('MyHostname', null, null);\n    var request = new EchoRequest();\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(200, {'Content-Type': 'application/grpc-web-text'},\n                  // A valid grpc-web frame, but contains an invalid\n                  // protobuf payload.\n                  'AAAAAAUKCgoKCg==');\n    };\n    var call = echoService.echo(\n      request, {}, function(err, response) {\n        if (response) {\n          assert.fail('should not receive response');\n        }\n        assert.equal(13 /* StatusCode.INTERNAL */, err.code);\n        assert.equal(true, err.message.toLowerCase().includes('deserializing'));\n        assert.equal(true, err.message.toLowerCase().includes('error'));\n        done();\n    });\n    call.on('data', (response) => {\n      assert.fail('should not receive response this way');\n    });\n    call.on('error', (error) => {\n      assert.fail('should not receive error this way');\n    });\n  });\n\n  it('should error out on invalid response body', function(done) {\n    execSync(genCodeCmd);\n    const {EchoServiceClient} = require(genCodePath);\n    const {EchoRequest} = require(protoGenCodePath);\n    var echoService = new EchoServiceClient('MyHostname', null, null);\n    var request = new EchoRequest();\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(200, {'Content-Type': 'application/grpc-web-text'},\n                  // An invalid response body. Should trip up in the\n                  // stream parser.\n                  'ZZZZZ');\n    };\n    var call = echoService.echo(\n      request, {}, function(err, response) {\n        if (response) {\n          assert.fail('should not receive response');\n        }\n        assert.equal(2, err.code);\n        assert.equal(true, err.message.toLowerCase().includes(\n          'error in parsing response body'));\n        done();\n    });\n    call.on('data', (response) => {\n      assert.fail('should not receive response this way');\n    });\n    call.on('error', (error) => {\n      assert.fail('should not receive error this way');\n    });\n  });\n\n  it('should not receive response on non-ok status', function(done) {\n    done = multiDone(done, 2);\n    execSync(genCodeCmd);\n    const {EchoServiceClient} = require(genCodePath);\n    const {EchoRequest} = require(protoGenCodePath);\n    var echoService = new EchoServiceClient('MyHostname', null, null);\n    var request = new EchoRequest();\n    request.setMessage('aaa');\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        200, {'Content-Type': 'application/grpc-web-text'},\n        // a single data frame with an 'aaa' message, followed by,\n        // a trailer frame with content 'grpc-status: 2\\d\\ax-custom-1: ababab'\n        'AAAAAAUKA2FhYYAAAAAkZ3JwYy1zdGF0dXM6IDINCngtY3VzdG9tLTE6IGFiYWJhYg0K'\n      );\n    };\n    var call = echoService.echo(\n      request, {'custom-header-1':'value1'},\n      function(err, response) {\n        if (response) {\n          assert.fail('should not have received response with non-OK status');\n        } else {\n          assert.equal(2, err.code);\n        }\n        done();\n      });\n    call.on('status', function(status) {\n      assert.equal(2, status.code);\n      assert.equal('object', typeof status.metadata);\n      assert.equal(false, 'grpc-status' in status.metadata);\n      assert.equal(true, 'x-custom-1' in status.metadata);\n      assert.equal('ababab', status.metadata['x-custom-1']);\n      done();\n    });\n    call.on('error', (error) => {\n      assert.fail('error callback should not be called for unary calls');\n    });\n  });\n\n});\n\ndescribe('grpc-web generated code (closure+grpcwebtext)', function() {\n  const oldXMLHttpRequest = global.XMLHttpRequest;\n\n  const compiledCodePath = path.resolve(__dirname, './generated/compiled.js');\n  const genCodeCmd =\n    'protoc -I=./test/protos echo.proto ' +\n    '--js_out=import_style=closure:./test/generated ' +\n    '--grpc-web_out=import_style=closure,mode=grpcwebtext:./test/generated';\n  const cwd = process.cwd();\n  const jsPaths = [\n    \".\",\n    \"../../../javascript\",\n    \"../node_modules/google-closure-library\",\n    \"../../../third_party/protobuf/js\",\n  ].map(jsPath => path.relative(cwd, path.resolve(__dirname, jsPath)));\n  const closureArgs = [].concat(\n    jsPaths.map(jsPath => `--js=${jsPath}`),\n    [\n      `--entry_point=goog:proto.grpc.gateway.testing.EchoAppClient`,\n      `--dependency_mode=PRUNE`,\n      `--js_output_file ./test/generated/compiled.js`,\n      `--output_wrapper=\"%output%module.exports = `+\n      `proto.grpc.gateway.testing;\"`,\n    ]\n  );\n  const closureCmd = \"google-closure-compiler \" + closureArgs.join(' ');\n\n  before(function() {\n    ['protoc', 'protoc-gen-grpc-web'].map(prog => {\n      if (!commandExists(prog)) {\n        assert.fail(`${prog} is not installed`);\n      }\n    });\n    if (!fs.existsSync(path.resolve(\n      __dirname, '../../../javascript/net/grpc/web/grpcwebclientbase.js'))) {\n      this.skip();\n    }\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n    fs.mkdirSync(path.resolve(__dirname, GENERATED_CODE_PATH));\n  });\n\n  beforeEach(function() {\n    MockXMLHttpRequest = mockXmlHttpRequest.newMockXhr()\n    global.XMLHttpRequest = MockXMLHttpRequest;\n  });\n\n  afterEach(function() {\n    global.XMLHttpRequest = oldXMLHttpRequest;\n  });\n\n  after(function() {\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n  });\n\n  it('should exist', function() {\n    execSync(genCodeCmd);\n    execSync(closureCmd);\n    assert.equal(true, fs.existsSync(compiledCodePath));\n  });\n\n  it('should import', function() {\n    var compiled = require(compiledCodePath);\n    echoAppClient = new compiled.EchoAppClient();\n    assert.equal('function', typeof echoAppClient.echo);\n  });\n\n  it('should send unary request', function(done) {\n    var compiled = require(compiledCodePath);\n    echoAppClient = new compiled.EchoAppClient();\n    MockXMLHttpRequest.onSend = function(xhr) {\n      assert.equal(\"AAAAAAUKA2FiYw==\", xhr.body);\n      done();\n    }\n    echoAppClient.echo('abc', () => {});\n  });\n\n  it('should receive unary response', function(done) {\n    var compiled = require(compiledCodePath);\n    echoAppClient = new compiled.EchoAppClient();\n    MockXMLHttpRequest.onSend = function(xhr) {\n      assert.equal(\"AAAAAAUKA2FiYw==\", xhr.body);\n      xhr.respond(200, {'Content-Type': 'application/grpc-web-text'},\n                  \"AAAAAAUKA2FiYw==\");\n    }\n    echoAppClient.echo('abc', function(err, response) {\n      assert.equal(\"abc\", response.getMessage());\n      done();\n    });\n  });\n});\n\ndescribe('grpc-web generated code: callbacks tests', function() {\n  const protoGenCodePath = path.resolve(__dirname, './echo_pb.js');\n  const genCodePath = path.resolve(__dirname, './echo_grpc_web_pb.js');\n\n  const genCodeCmd =\n    'protoc -I=./test/protos echo.proto ' +\n    '--js_out=import_style=commonjs:./test ' +\n    '--grpc-web_out=import_style=commonjs,mode=grpcwebtext:./test';\n\n  var echoService;\n  var request;\n\n  before(function() {\n    MockXMLHttpRequest = mockXmlHttpRequest.newMockXhr()\n    global.XMLHttpRequest = MockXMLHttpRequest;\n\n    execSync(genCodeCmd);\n    const {EchoServiceClient} = require(genCodePath);\n    const {EchoRequest} = require(protoGenCodePath);\n    echoService = new EchoServiceClient('MyHostname', null, null);\n    request = new EchoRequest();\n    request.setMessage('aaa');\n  });\n\n  after(function() {\n    if (fs.existsSync(protoGenCodePath)) {\n      fs.unlinkSync(protoGenCodePath);\n    }\n    if (fs.existsSync(genCodePath)) {\n      fs.unlinkSync(genCodePath);\n    }\n  });\n\n  it('should receive initial metadata callback', function(done) {\n    done = multiDone(done, 2);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        200, {\n          'Content-Type': 'application/grpc-web-text',\n          'initial-header-1': 'value1',\n        },\n        // a single data frame with message 'aaa'\n        'AAAAAAUKA2FhYQ==');\n    };\n    var call = echoService.echo(\n      request, {},\n      function(err, response) {\n        if (err) {\n          assert.fail('should not have received error');\n        } else {\n          assert.equal('aaa', response.getMessage());\n        }\n        done();\n      }\n    );\n    call.on('metadata', (metadata) => {\n      assert('initial-header-1' in metadata);\n      assert.equal('value1', metadata['initial-header-1']);\n      done();\n    });\n  });\n\n  it('should receive error, on http error', function(done) {\n    done = multiDone(done, 2);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        400, {'Content-Type': 'application/grpc-web-text'});\n    };\n    var call = echoService.echo(\n      request, {},\n      function(err, response) {\n        if (response) {\n          assert.fail('should not have received response with non-OK status');\n        } else {\n          assert.equal(3, err.code); // http error 400 mapped to grpc error 3\n        }\n        done();\n      }\n    );\n    call.on('status', (status) => {\n      assert.equal(3, status.code);\n      done();\n    });\n    call.on('error', (error) => {\n      assert.fail('error callback should not be called for unary calls');\n    });\n  });\n\n  it('should receive error, on grpc error', function(done) {\n    done = multiDone(done, 2);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        200, {'Content-Type': 'application/grpc-web-text'},\n        // a single data frame with an 'aaa' message, followed by,\n        // a trailer frame with content 'grpc-status: 2\\d\\ax-custom-1: ababab'\n        'AAAAAAUKA2FhYYAAAAAkZ3JwYy1zdGF0dXM6IDINCngtY3VzdG9tLTE6IGFiYWJhYg0K'\n      );\n    };\n    var call = echoService.echo(\n      request, {},\n      function(err, response) {\n        if (response) {\n          assert.fail('should not have received response with non-OK status');\n        } else {\n          assert.equal(2, err.code);\n          assert.equal(true, 'x-custom-1' in err.metadata);\n          assert.equal('ababab', err.metadata['x-custom-1']);\n        }\n        done();\n      }\n    );\n    // also should receive trailing status callback\n    call.on('status', (status) => {\n      // grpc-status should not be part of trailing metadata\n      assert.equal(false, 'grpc-status' in status.metadata);\n      assert.equal(true, 'x-custom-1' in status.metadata);\n      assert.equal('ababab', status.metadata['x-custom-1']);\n      done();\n    });\n    call.on('error', (error) => {\n      assert.fail('error callback should not be called for unary calls');\n    });\n  });\n\n  it('should receive error, on response header error', function(done) {\n    done = multiDone(done, 2);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        200, {\n          'Content-Type': 'application/grpc-web-text',\n          'grpc-status': 2,\n          'grpc-message': 'some error',\n      });\n    };\n    var call = echoService.echo(\n      request, {},\n      function(err, response) {\n        if (response) {\n          assert.fail('should not have received response with non-OK status');\n        } else {\n          assert.equal(2, err.code);\n          assert.equal('some error', err.message);\n        }\n        done();\n      }\n    );\n    call.on('status', (status) => {\n      assert.equal(2, status.code);\n      done();\n    });\n    call.on('error', (error) => {\n      assert.fail('error callback should not be called for unary calls');\n    });\n  });\n\n  it('should receive status callback', function(done) {\n    done = multiDone(done, 2);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        200, {'Content-Type': 'application/grpc-web-text'},\n        // a single data frame with an 'aaa' message, followed by,\n        // a trailer frame with content 'grpc-status: 0\\d\\ax-custom-1: ababab'\n        'AAAAAAUKA2FhYYAAAAAkZ3JwYy1zdGF0dXM6IDANCngtY3VzdG9tLTE6IGFiYWJhYg0K'\n      );\n    };\n    var call = echoService.echo(\n      request, {},\n      function(err, response) {\n        if (err) {\n          assert.fail('should not receive error');\n        }\n        assert(response);\n        assert.equal('aaa', response.getMessage());\n        done();\n      }\n    );\n    call.on('status', (status) => {\n      assert.equal(0, status.code);\n      // grpc-status should not be part of trailing metadata\n      assert.equal(false, 'grpc-status' in status.metadata);\n      assert.equal(true, 'x-custom-1' in status.metadata);\n      assert.equal('ababab', status.metadata['x-custom-1']);\n      done();\n    });\n    call.on('error', (error) => {\n      assert.fail('error callback should not be called for unary calls');\n    });\n  });\n\n  it('should trigger multiple callbacks on same event', function(done) {\n    done = multiDone(done, 2);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        400, {'Content-Type': 'application/grpc-web-text'});\n    };\n    var call = echoService.serverStreamingEcho(request, {});\n\n    call.on('data', (response) => {\n      assert.fail('should not have received a data callback');\n    });\n    call.on('error', (error) => {\n      assert.equal(3, error.code); // http error 400 mapped to grpc error 3\n      done();\n    });\n    call.on('error', (error) => {\n      assert.equal(3, error.code); // http error 400 mapped to grpc error 3\n      done();\n    });\n  });\n\n  it('should be able to remove callback', function(done) {\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        400, {'Content-Type': 'application/grpc-web-text'});\n    };\n    var call = echoService.serverStreamingEcho(request, {});\n    const callbackA = (error) => {\n      assert.equal(3, error.code); // http error 400 mapped to grpc error 3\n      done();\n    }\n    const callbackB = (error) => {\n      assert.fail('should not be called');\n    }\n    call.on('error', callbackA);\n    call.on('error', callbackB);\n    call.removeListener('error', callbackB);\n  });\n\n  it('should receive initial metadata callback (streaming)', function(done) {\n    done = multiDone(done, 2);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        200, {\n          'Content-Type': 'application/grpc-web-text',\n          'initial-header-1': 'value1',\n        },\n        // a single data frame with message 'aaa'\n        'AAAAAAUKA2FhYQ==');\n    };\n    var call = echoService.serverStreamingEcho(request, {});\n    call.on('data', (response) => {\n      assert.equal('aaa', response.getMessage());\n      done();\n    });\n    call.on('metadata', (metadata) => {\n      assert('initial-header-1' in metadata);\n      assert.equal('value1', metadata['initial-header-1']);\n      done();\n    });\n  });\n\n  it('should receive error, on http error (streaming)', function(done) {\n    done = multiDone(done, 2);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        400, {'Content-Type': 'application/grpc-web-text'});\n    };\n    var call = echoService.serverStreamingEcho(request, {});\n    call.on('data', (response) => {\n      assert.fail('should not receive data response');\n    });\n    call.on('status', (status) => {\n      assert.equal(3, status.code);\n      done();\n    });\n    call.on('error', (error) => {\n      assert.equal(3, error.code);\n      done();\n    });\n  });\n\n  it('should receive error, on grpc error (streaming)', function(done) {\n    done = multiDone(done, 3);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        200, {'Content-Type': 'application/grpc-web-text'},\n        // a single data frame with an 'aaa' message, followed by,\n        // a trailer frame with content 'grpc-status: 2\\d\\ax-custom-1: ababab'\n        'AAAAAAUKA2FhYYAAAAAkZ3JwYy1zdGF0dXM6IDINCngtY3VzdG9tLTE6IGFiYWJhYg0K'\n      );\n    };\n    var call = echoService.serverStreamingEcho(request, {});\n    call.on('data', (response) => {\n      // because this is a streaming call, we should still receive data\n      // callbacks if the error comes in with the trailer frame\n      assert.equal('aaa', response.getMessage());\n      done();\n    });\n    call.on('error', (error) => {\n      assert.equal(2, error.code);\n      assert.equal(true, 'x-custom-1' in error.metadata);\n      assert.equal('ababab', error.metadata['x-custom-1']);\n      done();\n    });\n    call.on('status', (status) => {\n      assert.equal(2, status.code);\n      // grpc-status should not be part of trailing metadata\n      assert.equal(false, 'grpc-status' in status.metadata);\n      assert.equal(true, 'x-custom-1' in status.metadata);\n      assert.equal('ababab', status.metadata['x-custom-1']);\n      done();\n    });\n  });\n\n  it('should receive error, on response header error (streaming)',\n     function(done) {\n    done = multiDone(done, 2);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        200, {\n          'Content-Type': 'application/grpc-web-text',\n          'grpc-status': 2,\n          'grpc-message': 'some error',\n      });\n    };\n    var call = echoService.serverStreamingEcho(request, {});\n    call.on('error', (error) => {\n      assert.equal(2, error.code);\n      assert.equal('some error', error.message);\n      done();\n    });\n    call.on('status', (status) => {\n      assert.equal(2, status.code);\n      assert.equal('some error', status.details);\n      done();\n    });\n  });\n\n  it('should receive status callback (streaming)', function(done) {\n    done = multiDone(done, 2);\n    MockXMLHttpRequest.onSend = function(xhr) {\n      xhr.respond(\n        200, {'Content-Type': 'application/grpc-web-text'},\n        // a single data frame with an 'aaa' message, followed by,\n        // a trailer frame with content 'grpc-status: 0\\d\\ax-custom-1: ababab'\n        'AAAAAAUKA2FhYYAAAAAkZ3JwYy1zdGF0dXM6IDANCngtY3VzdG9tLTE6IGFiYWJhYg0K'\n      );\n    };\n    var call = echoService.serverStreamingEcho(request, {});\n    call.on('data', (response) => {\n        assert(response);\n        assert.equal('aaa', response.getMessage());\n        done();\n    });\n    call.on('status', (status) => {\n      assert.equal(0, status.code);\n      // grpc-status should not be part of trailing metadata\n      assert.equal(false, 'grpc-status' in status.metadata);\n      assert.equal(true, 'x-custom-1' in status.metadata);\n      assert.equal('ababab', status.metadata['x-custom-1']);\n      done();\n    });\n    call.on('error', (error) => {\n      assert.fail('error callback should not be called for unary calls');\n    });\n  });\n\n});\n"
  },
  {
    "path": "packages/grpc-web/test/gulpfile.js",
    "content": "const gulp = require('gulp');\nconst gulpEval = require('gulp-eval');\n\ngulp.task('gen-code-eval-test', () =>\n  gulp.src('./generated/foo_grpc_web_pb.js')\n      .pipe(gulpEval())\n);\n"
  },
  {
    "path": "packages/grpc-web/test/plugin_test.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nconst assert = require('assert');\nconst execSync = require('child_process').execSync;\nconst commandExists = require('command-exists').sync;\nconst fs = require('fs');\nconst path = require('path');\nconst removeDirectory = require('./common.js').removeDirectory;\nconst GENERATED_CODE_PATH = require('./common.js').GENERATED_CODE_PATH;\nconst mockXmlHttpRequest = require('mock-xmlhttprequest');\n\nvar MockXMLHttpRequest;\n\n\ndescribe('grpc-web plugin test, with subdirectories', function() {\n  const oldXMLHttpRequest = global.XMLHttpRequest;\n\n  const genCodePath1 = path.resolve(\n    __dirname, GENERATED_CODE_PATH + '/myapi/v1/myapi_pb.js');\n  const genCodePath2 = path.resolve(\n    __dirname, GENERATED_CODE_PATH + '/otherapi/v1/otherapi_pb.js');\n  const genCodePath3 = path.resolve(\n    __dirname, GENERATED_CODE_PATH + '/myapi/v1/myapi_grpc_web_pb.js');\n\n  const genCodeCmd =\n    'protoc -I=./test/protos ' +\n    './test/protos/myapi/v1/myapi.proto ' +\n    './test/protos/otherapi/v1/otherapi.proto ' +\n    '--js_out=import_style=commonjs:./test/generated ' +\n    '--grpc-web_out=import_style=commonjs,mode=grpcwebtext:./test/generated';\n\n  before(function() {\n    ['protoc', 'protoc-gen-grpc-web'].map(prog => {\n      if (!commandExists(prog)) {\n        assert.fail(`${prog} is not installed`);\n      }\n    });\n  });\n\n  beforeEach(function() {\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n    fs.mkdirSync(path.resolve(__dirname, GENERATED_CODE_PATH));\n    MockXMLHttpRequest = mockXmlHttpRequest.newMockXhr();\n    global.XMLHttpRequest = MockXMLHttpRequest;\n  });\n\n  afterEach(function() {\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n    global.XMLHttpRequest = oldXMLHttpRequest;\n  });\n\n  it('should exist', function() {\n    execSync(genCodeCmd);\n    assert.equal(true, fs.existsSync(genCodePath1));\n    assert.equal(true, fs.existsSync(genCodePath2));\n    assert.equal(true, fs.existsSync(genCodePath3));\n  });\n\n  it('should import', function() {\n    execSync(genCodeCmd);\n\n    const {OtherThing} = require(genCodePath2);\n    var otherThing = new OtherThing();\n    otherThing.setValue('abc');\n    assert.equal('abc', otherThing.getValue());\n\n    const {MyServiceClient} = require(genCodePath3);\n    var myClient = new MyServiceClient(\"MyHostname\", null, null);\n    assert.equal('function', typeof myClient.doThis);\n  });\n\n  it('should send unary request', function(done) {\n    execSync(genCodeCmd);\n\n    const {OtherThing} = require(genCodePath2);\n    var otherThing = new OtherThing();\n    otherThing.setValue('abc');\n\n    const {MyServiceClient} = require(genCodePath3);\n    var myClient = new MyServiceClient(\"MyHostname\", null, null);\n\n    MockXMLHttpRequest.onSend = function(xhr) {\n      assert.equal(\"AAAAAAUKA2FiYw==\", xhr.body);\n      assert.equal(\"MyHostname/myproject.myapi.v1.MyService/DoThis\", xhr.url);\n      done();\n    };\n    myClient.doThis(otherThing);\n  });\n});\n\n\ndescribe('grpc-web plugin test, with multiple input files', function() {\n  const genCodePath1 = path.resolve(\n    __dirname, GENERATED_CODE_PATH + '/myapi/v1/myapi_pb.js');\n  const genCodePath2 = path.resolve(\n    __dirname, GENERATED_CODE_PATH + '/otherapi/v1/otherapi_pb.js');\n  const genCodePath3 = path.resolve(\n    __dirname, GENERATED_CODE_PATH + '/myapi/v1/myapi_grpc_web_pb.js');\n  const genCodePath4 = path.resolve(\n    __dirname, GENERATED_CODE_PATH + '/myapi/v1/myapi-two_grpc_web_pb.js');\n\n  const genCodeCmd =\n    'protoc -I=./test/protos ' +\n    './test/protos/myapi/v1/myapi.proto ' +\n    './test/protos/myapi/v1/myapi-two.proto ' +\n    './test/protos/otherapi/v1/otherapi.proto ' +\n    '--js_out=import_style=commonjs:./test/generated ' +\n    '--grpc-web_out=import_style=commonjs,mode=grpcwebtext:./test/generated';\n\n  before(function() {\n    ['protoc', 'protoc-gen-grpc-web'].map(prog => {\n      if (!commandExists(prog)) {\n        assert.fail(`${prog} is not installed`);\n      }\n    });\n  });\n\n  beforeEach(function() {\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n    fs.mkdirSync(path.resolve(__dirname, GENERATED_CODE_PATH));\n  });\n\n  afterEach(function() {\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n  });\n\n  it('should exist', function() {\n    execSync(genCodeCmd);\n    assert.equal(true, fs.existsSync(genCodePath1));\n    assert.equal(true, fs.existsSync(genCodePath2));\n    assert.equal(true, fs.existsSync(genCodePath3));\n    assert.equal(true, fs.existsSync(genCodePath4));\n  });\n\n  it('should import', function() {\n    execSync(genCodeCmd);\n\n    const {OtherThing} = require(genCodePath2);\n    var otherThing = new OtherThing();\n    otherThing.setValue('abc');\n    assert.equal('abc', otherThing.getValue());\n\n    const {MyServiceClient} = require(genCodePath3);\n    var myClient = new MyServiceClient(\"MyHostname\", null, null);\n    assert.equal('function', typeof myClient.doThis);\n\n    const {MyServiceBClient} = require(genCodePath4);\n    var myClientB = new MyServiceBClient(\"MyHostname\", null, null);\n    assert.equal('function', typeof myClientB.doThat);\n  });\n});\n\n\ndescribe('grpc-web plugin test, proto with no package', function() {\n  const genCodePath1 = path.resolve(\n    __dirname, GENERATED_CODE_PATH + '/nopackage_pb.js');\n  const genCodePath2 = path.resolve(\n    __dirname, GENERATED_CODE_PATH + '/nopackage_grpc_web_pb.js');\n\n  const genCodeCmd =\n    'protoc -I=./test/protos ' +\n    './test/protos/nopackage.proto ' +\n    '--js_out=import_style=commonjs:./test/generated ' +\n    '--grpc-web_out=import_style=commonjs,mode=grpcwebtext:./test/generated';\n\n  before(function() {\n    ['protoc', 'protoc-gen-grpc-web'].map(prog => {\n      if (!commandExists(prog)) {\n        assert.fail(`${prog} is not installed`);\n      }\n    });\n\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n    fs.mkdirSync(path.resolve(__dirname, GENERATED_CODE_PATH));\n    MockXMLHttpRequest = mockXmlHttpRequest.newMockXhr();\n    global.XMLHttpRequest = MockXMLHttpRequest;\n\n    execSync(genCodeCmd);\n    assert.equal(true, fs.existsSync(genCodePath1));\n    assert.equal(true, fs.existsSync(genCodePath2));\n  });\n\n  after(function() {\n    removeDirectory(path.resolve(__dirname, GENERATED_CODE_PATH));\n  });\n\n  it('should import', function() {\n    const {HelloRequest} = require(genCodePath1);\n    var request = new HelloRequest();\n\n    request.setName('abc');\n    assert.equal('abc', request.getName());\n  });\n\n  it('callback-based generated client: should exist', function() {\n    const {GreeterClient} = require(genCodePath2);\n    var myClient = new GreeterClient(\"MyHostname\", null, null);\n\n    assert.equal('function', typeof myClient.sayHello);\n  });\n\n  it('promise-based generated client: should exist', function() {\n    const {HelloRequest} = require(genCodePath1);\n    const {GreeterPromiseClient} = require(genCodePath2);\n    var myClient = new GreeterPromiseClient(\"MyHostname\", null, null);\n\n    assert.equal('function', typeof myClient.sayHello);\n\n    var p = myClient.sayHello(new HelloRequest(), {});\n    assert.equal('function', typeof p.then);\n  });\n});\n"
  },
  {
    "path": "packages/grpc-web/test/protos/echo.proto",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     https://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage grpc.gateway.testing;\n\nmessage EchoRequest {\n  string message = 1;\n  int32 value = 2;\n}\n\nmessage EchoResponse {\n  string message = 1;\n  // to test Request and Response having a different shape\n  string value = 2;\n}\n\nmessage ServerStreamingEchoRequest {\n  string message = 1;\n  int32 message_count = 2;\n  int32 message_interval = 3;\n}\n\nmessage ServerStreamingEchoResponse {\n  string message = 1;\n}\n\nenum Status {\n  UNKNOWN = 0;\n  SUCCESS = 1;\n}\n\nmessage EchoStatusRequest {\n  Status status = 1;\n}\n\nmessage EchoStatusResponse {\n  enum InternalStatus {\n    UNKNOWN = 0;\n    SUCCESS = 1;\n  }\n  InternalStatus status = 1;\n}\n\n\nservice EchoService {\n  rpc Echo(EchoRequest) returns (EchoResponse);\n  rpc ServerStreamingEcho(ServerStreamingEchoRequest)\n      returns (stream ServerStreamingEchoResponse);\n  rpc EchoStatus(EchoStatusRequest) returns (EchoStatusResponse);\n}\n"
  },
  {
    "path": "packages/grpc-web/test/protos/foo.proto",
    "content": "syntax = \"proto3\";\n\npackage Foo;\n\nimport \"models.proto\";\n\nmessage SimpleRequest {\n  string message = 1;\n}\n\nservice FooService {\n  rpc EchoEmpty(SimpleRequest) returns (models.SimpleMessage);\n}\n"
  },
  {
    "path": "packages/grpc-web/test/protos/models.proto",
    "content": "syntax = \"proto3\";\n\npackage models;\n\nmessage SimpleMessage {\n}\n"
  },
  {
    "path": "packages/grpc-web/test/protos/myapi/v1/myapi-two.proto",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     https://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage myproject.myapi.v1;\n\nimport \"otherapi/v1/otherapi.proto\";\n\nservice MyServiceB {\n  rpc DoThat(myproject.otherapi.v1.OtherThing) returns (myproject.otherapi.v1.OtherThing);\n}\n"
  },
  {
    "path": "packages/grpc-web/test/protos/myapi/v1/myapi.proto",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     https://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage myproject.myapi.v1;\n\nimport \"otherapi/v1/otherapi.proto\";\n\nmessage MyThing {\n  string message = 1;\n  myproject.otherapi.v1.OtherThing other_thing = 2;\n}\n\nservice MyService {\n  rpc DoThis(myproject.otherapi.v1.OtherThing) returns (myproject.otherapi.v1.OtherThing);\n}\n"
  },
  {
    "path": "packages/grpc-web/test/protos/nopackage.proto",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     https://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\nservice Greeter {\n  rpc SayHello (HelloRequest) returns (HelloReply);\n}\n\nmessage HelloRequest {\n  string name = 1;\n}\n\nmessage HelloReply {\n  string message = 1;\n}\n"
  },
  {
    "path": "packages/grpc-web/test/protos/otherapi/v1/otherapi.proto",
    "content": "// Copyright 2018 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     https://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage myproject.otherapi.v1;\n\nmessage OtherThing {\n  string value = 1;\n}\n"
  },
  {
    "path": "packages/grpc-web/test/protos/test01.proto",
    "content": "syntax = \"proto3\";\n\nmessage MessageOuter {\n  message MessageInner {\n    int32 value = 1;\n  }\n\n  enum EnumInner {\n    DEFAULT = 0;\n  }\n\n  repeated MessageInner someProp = 1;\n  EnumOuter someEnum = 2;\n  EnumInner anotherEnum = 3;\n}\n\nenum EnumOuter {\n  DEFAULT = 0;\n}\n"
  },
  {
    "path": "packages/grpc-web/test/protos/test02.proto",
    "content": "syntax = \"proto3\";\nimport \"test03.proto\";\n\nservice MyService {\n  rpc addOne(Integer) returns (Integer);\n}\n"
  },
  {
    "path": "packages/grpc-web/test/protos/test03.proto",
    "content": "syntax = \"proto3\";\n\nmessage Integer {\n}\n"
  },
  {
    "path": "packages/grpc-web/test/tsc-tests/client01.ts",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\nimport * as grpcWeb from 'grpc-web';\n\nimport {MessageOuter} from './generated/test01_pb';\n\nlet inner1 = new MessageOuter.MessageInner();\ninner1.setValue(123);\nlet msgOuter = new MessageOuter();\nmsgOuter.setSomepropList([inner1]);\n\nexport {msgOuter}\n"
  },
  {
    "path": "packages/grpc-web/test/tsc-tests/client02.ts",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\nimport * as grpcWeb from 'grpc-web';\n\nimport {Integer} from './generated/test03_pb';\nimport {MyServiceClient} from './generated/Test02ServiceClientPb';\n\nconst service = new MyServiceClient('http://mydummy.com', null, null);\nconst req = new Integer();\n\nservice.addOne(req, {}, (err: grpcWeb.RpcError, resp: Integer) => {\n});\n"
  },
  {
    "path": "packages/grpc-web/test/tsc-tests/client03.ts",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\nimport * as grpcWeb from 'grpc-web';\n\nimport {EchoRequest, EchoResponse} from './generated/echo_pb';\nimport {EchoServiceClient} from './generated/echo_grpc_web_pb';\n\n// The StreamInterceptor interface is for the callback-based client.\nclass MyStreamInterceptor implements grpcWeb.StreamInterceptor<\n  EchoRequest, EchoResponse> {\n  intercept(\n    request: grpcWeb.Request<EchoRequest, EchoResponse>,\n    invoker: (request: grpcWeb.Request<EchoRequest, EchoResponse>) =>\n      grpcWeb.ClientReadableStream<EchoResponse>) {\n    class InterceptedStream implements grpcWeb.ClientReadableStream<\n      EchoResponse> {\n      stream: grpcWeb.ClientReadableStream<EchoResponse>;\n      constructor(stream: grpcWeb.ClientReadableStream<EchoResponse>) {\n        this.stream = stream;\n      };\n      on(eventType: string, callback: any) {\n        if (eventType == 'data') {\n          const newCallback = (response: EchoResponse) => {\n            response.setMessage('[-in-]'+response.getMessage());\n            callback(response);\n          };\n          this.stream.on(eventType, newCallback);\n        } else if (eventType == 'error') {\n          this.stream.on('error', callback);\n        } else if (eventType == 'metadata') {\n          this.stream.on('metadata', callback);\n        } else if (eventType == 'status') {\n          this.stream.on('status', callback);\n        } else if (eventType == 'end') {\n          this.stream.on('end', callback);\n        }\n        return this;\n      };\n      removeListener(eventType: string, callback: any) {\n      }\n      cancel() {}\n    }\n    var reqMsg = request.getRequestMessage();\n    reqMsg.setMessage('[-out-]'+reqMsg.getMessage());\n    return new InterceptedStream(invoker(request));\n  };\n}\n\nvar opts = {'streamInterceptors' : [new MyStreamInterceptor()]};\n\nconst echoService = new EchoServiceClient('http://localhost:8080', null, opts);\n\nexport {echoService, EchoRequest}\n"
  },
  {
    "path": "packages/grpc-web/test/tsc-tests/client04.ts",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\nimport * as grpcWeb from 'grpc-web';\n\nimport {EchoRequest, EchoResponse} from './generated/echo_pb';\nimport {EchoServicePromiseClient} from './generated/echo_grpc_web_pb';\n\n// The UnaryInterceptor interface is for the promise-based client.\nclass MyUnaryInterceptor implements grpcWeb.UnaryInterceptor<\n  EchoRequest, EchoResponse> {\n    intercept(request: grpcWeb.Request<EchoRequest, EchoResponse>,\n              invoker: (request: grpcWeb.Request<EchoRequest, EchoResponse>) =>\n      Promise<grpcWeb.UnaryResponse<EchoRequest, EchoResponse>>) {\n      const reqMsg = request.getRequestMessage();\n      reqMsg.setMessage('[-out-]' + reqMsg.getMessage());\n      return invoker(request).then((response: grpcWeb.UnaryResponse<\n        EchoRequest, EchoResponse>) => {\n          let result = '<-InitialMetadata->';\n          let initialMetadata = response.getMetadata();\n          for (let i in initialMetadata) {\n            result += i + ': ' + initialMetadata[i];\n          }\n          result += '<-TrailingMetadata->';\n          let trailingMetadata = response.getStatus().metadata;\n          for (let i in trailingMetadata) {\n            result += i + ': ' + trailingMetadata[i];\n          }\n          const responseMsg = response.getResponseMessage();\n          result += '[-in-]' + responseMsg.getMessage();\n          responseMsg.setMessage(result);\n          return response;\n        });\n    }\n  }\n\nvar opts = {'unaryInterceptors' : [new MyUnaryInterceptor()]};\n\nconst echoService = new EchoServicePromiseClient('http://localhost:8080',\n                                                 null, opts);\n\nexport {echoService, EchoRequest}\n"
  },
  {
    "path": "packages/grpc-web/test/tsc-tests/client05.ts",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\nimport * as grpcWeb from 'grpc-web';\n\nimport {EchoRequest, EchoResponse,\n        ServerStreamingEchoRequest,\n        ServerStreamingEchoResponse} from './generated/echo_pb';\nimport {EchoServiceClient} from './generated/echo_grpc_web_pb';\n\nconst echoService = new EchoServiceClient('http://localhost:8080', null, null);\n\nlet req = new EchoRequest();\nreq.setMessage('aaa');\n\n// this test tries to make sure that these types are as accurate as possible\n\nlet call1 : grpcWeb.ClientReadableStream<EchoResponse> =\n  echoService.echo(req, {}, (err: grpcWeb.RpcError,\n                             response: EchoResponse) => {\n                             });\n\ncall1\n  .on('status', (status: grpcWeb.Status) => {\n  })\n  .on('metadata', (metadata: grpcWeb.Metadata) => {\n  });\n\nlet call2 : grpcWeb.ClientReadableStream<ServerStreamingEchoResponse> =\n  echoService.serverStreamingEcho(new ServerStreamingEchoRequest(), {});\n\ncall2\n  .on('data', (response: ServerStreamingEchoResponse) => {\n  })\n  .on('error', (error: grpcWeb.RpcError) => {\n  });\n"
  },
  {
    "path": "packages/grpc-web/test/tsc-tests/client06.ts",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\nimport * as grpcWeb from 'grpc-web';\n\nimport {EchoRequest, EchoResponse} from './generated/echo_pb';\nimport {EchoServicePromiseClient} from './generated/echo_grpc_web_pb';\n\nconst echoService = new EchoServicePromiseClient(\n  'http://localhost:8080', null, null);\n\nlet req = new EchoRequest();\nreq.setMessage('aaa');\n\n// this test tries to make sure that these types are as accurate as possible\n\nlet p1 : Promise<EchoResponse> = echoService.echo(req, {});\n\n// why does the .then() add this extra 'void' type to the returned Promise?\nlet p2 : Promise<void | EchoResponse> = p1.then((response: EchoResponse) => {\n});\n"
  },
  {
    "path": "packages/grpc-web/test/tsc_test.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nconst assert = require('assert');\nconst execSync = require('child_process').execSync;\nconst fs = require('fs');\nconst path = require('path');\nconst removeDirectory = require('./common.js').removeDirectory;\nconst mockXmlHttpRequest = require('mock-xmlhttprequest');\n\nvar MockXMLHttpRequest;\n\nfunction relativePath(relPath) {\n  return path.resolve(__dirname, relPath);\n}\nfunction cleanup() {\n  removeDirectory(relativePath('./tsc-tests/dist'));\n  removeDirectory(relativePath('./tsc-tests/generated'));\n}\nfunction createGeneratedCodeDir() {\n  fs.mkdirSync(relativePath('./tsc-tests/generated'));\n}\nfunction assertFileExists(relPath) {\n  assert.equal(true, fs.existsSync(relativePath(relPath)));\n}\nfunction multiDone(done, count) {\n  return function() {\n    count -= 1;\n    if (count <= 0) {\n      done();\n    }\n  };\n}\nfunction runTscCmd(tscCmd) {\n  try {\n    execSync(tscCmd, {cwd: relativePath('./tsc-tests')});\n  } catch (e) {\n    assert.fail(e.stdout);\n  }\n}\nconst outputDir = './test/tsc-tests/generated';\n// --skipLibCheck is needed because some of our node_modules/ targets es6 but\n// our test doesn't pass with `--target es6`\n// TODO: Find out how we can enable --target es6!\nconst tscCompilerOptions =\n    `--allowJs --strict --noImplicitReturns --skipLibCheck`;\n\ndescribe('tsc test01: nested messages', function() {\n  before(function() {\n    cleanup();\n    createGeneratedCodeDir();\n    execSync(`protoc -I=./test/protos test01.proto \\\n      --js_out=import_style=commonjs:${outputDir} \\\n      --grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:${outputDir}`);\n  });\n\n  after(function() {\n    cleanup();\n  });\n\n  it('generated code should exist', function() {\n    assertFileExists('./tsc-tests/generated/test01_pb.js');\n    assertFileExists('./tsc-tests/generated/test01_pb.d.ts');\n  });\n\n  it('tsc should run and export', function() {\n    runTscCmd(`tsc client01.ts generated/test01_pb.d.ts generated/test01_pb.js \\\n      ${tscCompilerOptions} --outDir ./dist`);\n\n    // check for the tsc output\n    assertFileExists('./tsc-tests/dist/client01.js');\n    assertFileExists('./tsc-tests/dist/generated/test01_pb.js');\n\n    // load the compiled js files and do some tests\n    const {msgOuter} = require(relativePath('./tsc-tests/dist/client01.js'));\n    assert.equal(123, msgOuter.getSomepropList()[0].getValue());\n  });\n});\n\ndescribe('tsc test02: simple rpc, messages in separate proto', function() {\n  before(function() {\n    cleanup();\n    createGeneratedCodeDir();\n    MockXMLHttpRequest = mockXmlHttpRequest.newMockXhr();\n    global.XMLHttpRequest = MockXMLHttpRequest;\n    execSync(`protoc -I=./test/protos test02.proto test03.proto \\\n      --js_out=import_style=commonjs:${outputDir} \\\n      --grpc-web_out=import_style=typescript,mode=grpcwebtext:${outputDir}`);\n  });\n\n  after(function() {\n    cleanup();\n  });\n\n  it('generated code should exist', function() {\n    assertFileExists('./tsc-tests/generated/Test02ServiceClientPb.ts');\n    assertFileExists('./tsc-tests/generated/test02_pb.js');\n    assertFileExists('./tsc-tests/generated/test02_pb.d.ts');\n    assertFileExists('./tsc-tests/generated/test03_pb.js');\n    assertFileExists('./tsc-tests/generated/test03_pb.d.ts');\n  });\n\n  it('tsc should run and export', function(done) {\n    runTscCmd(`tsc client02.ts generated/Test02ServiceClientPb.ts \\\n      generated/test02_pb.d.ts generated/test02_pb.js \\\n      generated/test03_pb.d.ts generated/test03_pb.js \\\n      ${tscCompilerOptions} --outDir ./dist`);\n\n    // check for the tsc output\n    assertFileExists('./tsc-tests/dist/client02.js');\n    assertFileExists('./tsc-tests/dist/generated/Test02ServiceClientPb.js');\n    assertFileExists('./tsc-tests/dist/generated/test02_pb.js');\n    assertFileExists('./tsc-tests/dist/generated/test03_pb.js');\n\n    // load the compiled js files and do some tests\n    MockXMLHttpRequest.onSend = function(xhr) {\n      assert.equal('http://mydummy.com/MyService/addOne', xhr.url);\n      assert.equal('AAAAAAA=', xhr.body);\n      done();\n    };\n    require(relativePath('./tsc-tests/dist/client02.js'));\n  });\n});\n\ndescribe('tsc test03: streamInterceptor', function() {\n  before(function() {\n    cleanup();\n    createGeneratedCodeDir();\n    MockXMLHttpRequest = mockXmlHttpRequest.newMockXhr();\n    global.XMLHttpRequest = MockXMLHttpRequest;\n    const genCmd = `protoc -I=./test/protos echo.proto \\\n      --js_out=import_style=commonjs:${outputDir} \\\n      --grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:${outputDir}`;\n    execSync(genCmd);\n  });\n\n  after(function() {\n    cleanup();\n  });\n\n  it('generated code should exist', function() {\n    assertFileExists('./tsc-tests/generated/echo_pb.js');\n    assertFileExists('./tsc-tests/generated/echo_pb.d.ts');\n    assertFileExists('./tsc-tests/generated/echo_grpc_web_pb.js');\n    assertFileExists('./tsc-tests/generated/echo_grpc_web_pb.d.ts');\n  });\n\n  it('tsc should run and export', function(done) {\n    done = multiDone(done, 3);\n    const tscCmd = `tsc client03.ts \\\n      generated/echo_pb.d.ts generated/echo_pb.js \\\n      generated/echo_grpc_web_pb.d.ts generated/echo_grpc_web_pb.js \\\n      ${tscCompilerOptions} --outDir ./dist`;\n    runTscCmd(tscCmd);\n\n    // check for the tsc output\n    assertFileExists('./tsc-tests/dist/client03.js');\n    assertFileExists('./tsc-tests/dist/generated/echo_pb.js');\n\n    const {echoService, EchoRequest} =\n      require(relativePath('./tsc-tests/dist/client03.js'));\n    assert.equal('function', typeof echoService.echo);\n    assert.equal('function', typeof echoService.serverStreamingEcho);\n\n    const req = new EchoRequest();\n    req.setMessage('aaa');\n    MockXMLHttpRequest.onSend = function(xhr) {\n      // The interceptor will attach \"[-out-]\" in front of our proto message.\n      // See the interceptor code in client03.ts.\n      // So by the time the proto is being sent by the underlying transport, it\n      // should contain the string \"[-out-]aaa\".\n      assert.equal('AAAAAAwKClstb3V0LV1hYWE=', xhr.body);\n\n      xhr.respond(200, {'Content-Type': 'application/grpc-web-text',\n                        'p': 'q'}, // add a piece of initial metadata\n                  // echo it back, plus a trailing metadata \"x: y\"\n                  'AAAAAAwKClstb3V0LV1hYWGAAAAABng6IHkNCg==');\n    };\n    // this is the callback-based client\n    var call = echoService.echo(req, {}, (err, response) => {\n      assert.ifError(err);\n      // Now, the interceptor will be invoked again on receiving the response\n      // from the server. It attaches an additional \"[-in-]\" string in front of\n      // the server response.\n      assert.equal('[-in-][-out-]aaa', response.getMessage());\n      done();\n    });\n    call.on('metadata', (initialMetadata) => {\n      assert('p' in initialMetadata);\n      assert(!('x' in initialMetadata));\n      assert.equal('q', initialMetadata['p']);\n      done();\n    });\n    call.on('status', (status) => {\n      assert('metadata' in status);\n      var trailingMetadata = status.metadata;\n      assert('x' in trailingMetadata);\n      assert(!('p' in trailingMetadata));\n      assert.equal('y', trailingMetadata['x']);\n      done();\n    });\n  });\n\n});\n\ndescribe('tsc test04: unaryInterceptor', function() {\n  before(function() {\n    cleanup();\n    createGeneratedCodeDir();\n    MockXMLHttpRequest = mockXmlHttpRequest.newMockXhr();\n    global.XMLHttpRequest = MockXMLHttpRequest;\n    const genCmd = `protoc -I=./test/protos echo.proto \\\n      --js_out=import_style=commonjs:${outputDir} \\\n      --grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:${outputDir}`;\n    execSync(genCmd);\n  });\n\n  after(function() {\n    cleanup();\n  });\n\n  it('generated code should exist', function() {\n    assertFileExists('./tsc-tests/generated/echo_pb.js');\n    assertFileExists('./tsc-tests/generated/echo_pb.d.ts');\n    assertFileExists('./tsc-tests/generated/echo_grpc_web_pb.js');\n    assertFileExists('./tsc-tests/generated/echo_grpc_web_pb.d.ts');\n  });\n\n  it('tsc should run and export', function(done) {\n    const tscCmd = `tsc client04.ts \\\n      generated/echo_pb.d.ts generated/echo_pb.js \\\n      generated/echo_grpc_web_pb.d.ts generated/echo_grpc_web_pb.js \\\n      ${tscCompilerOptions} --outDir ./dist`;\n    runTscCmd(tscCmd);\n\n    // check for the tsc output\n    assertFileExists('./tsc-tests/dist/client04.js');\n    assertFileExists('./tsc-tests/dist/generated/echo_pb.js');\n\n    const {echoService, EchoRequest} =\n      require(relativePath('./tsc-tests/dist/client04.js'));\n    assert.equal('function', typeof echoService.echo);\n    assert.equal('function', typeof echoService.serverStreamingEcho);\n\n    const req = new EchoRequest();\n    req.setMessage('aaa');\n    MockXMLHttpRequest.onSend = function(xhr) {\n      // The interceptor will attach \"[-out-]\" in front of our proto message.\n      // See the interceptor code in client04.ts.\n      // So by the time the proto is being sent by the underlying transport, it\n      // should contain the string \"[-out-]aaa\".\n      assert.equal('AAAAAAwKClstb3V0LV1hYWE=', xhr.body);\n\n      xhr.respond(200, {'Content-Type': 'application/grpc-web-text',\n                        'p': 'q'}, // add a piece of initial metadata\n                  // echo it back, plus a trailing metadata \"x: y\"\n                  'AAAAAAwKClstb3V0LV1hYWGAAAAABng6IHkNCg==');\n    };\n    // this is the promise-based client\n    echoService.echo(req, {}).then((response) => {\n      // Now, the interceptor will be invoked again on receiving the response\n      // from the server. See the initerceptor logic in client04.ts. It\n      // flattens both the initialMetadata and the trailingMetadata, and then\n      // attaches an additional \"[-in-]\" string in front of the server\n      // response.\n      assert.equal('<-InitialMetadata->p: q<-TrailingMetadata->x: y'+\n                   '[-in-][-out-]aaa', response.getMessage());\n      done();\n    });\n  });\n\n});\n\ndescribe('tsc test05: callback-based client', function() {\n  before(function() {\n    cleanup();\n    createGeneratedCodeDir();\n    MockXMLHttpRequest = mockXmlHttpRequest.newMockXhr();\n    global.XMLHttpRequest = MockXMLHttpRequest;\n    const genCmd = `protoc -I=./test/protos echo.proto \\\n      --js_out=import_style=commonjs:${outputDir} \\\n      --grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:${outputDir}`;\n    execSync(genCmd);\n  });\n\n  after(function() {\n    cleanup();\n  });\n\n  it('generated code should exist', function() {\n    assertFileExists('./tsc-tests/generated/echo_pb.js');\n    assertFileExists('./tsc-tests/generated/echo_pb.d.ts');\n    assertFileExists('./tsc-tests/generated/echo_grpc_web_pb.js');\n    assertFileExists('./tsc-tests/generated/echo_grpc_web_pb.d.ts');\n  });\n\n  it('tsc should run and export', function() {\n    const tscCmd = `tsc client05.ts \\\n      generated/echo_pb.d.ts generated/echo_pb.js \\\n      generated/echo_grpc_web_pb.d.ts generated/echo_grpc_web_pb.js \\\n      ${tscCompilerOptions} --outDir ./dist`;\n    // this test only makes sure the TS client code compiles successfully\n    runTscCmd(tscCmd);\n\n    // check for the tsc output\n    assertFileExists('./tsc-tests/dist/client05.js');\n    assertFileExists('./tsc-tests/dist/generated/echo_pb.js');\n  });\n});\n\ndescribe('tsc test06: promise-based client', function() {\n  before(function() {\n    cleanup();\n    createGeneratedCodeDir();\n    MockXMLHttpRequest = mockXmlHttpRequest.newMockXhr();\n    global.XMLHttpRequest = MockXMLHttpRequest;\n    const genCmd = `protoc -I=./test/protos echo.proto \\\n      --js_out=import_style=commonjs:${outputDir} \\\n      --grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:${outputDir}`;\n    execSync(genCmd);\n  });\n\n  after(function() {\n    cleanup();\n  });\n\n  it('generated code should exist', function() {\n    assertFileExists('./tsc-tests/generated/echo_pb.js');\n    assertFileExists('./tsc-tests/generated/echo_pb.d.ts');\n    assertFileExists('./tsc-tests/generated/echo_grpc_web_pb.js');\n    assertFileExists('./tsc-tests/generated/echo_grpc_web_pb.d.ts');\n  });\n\n  it('tsc should run and export', function() {\n    const tscCmd = `tsc client06.ts \\\n      generated/echo_pb.d.ts generated/echo_pb.js \\\n      generated/echo_grpc_web_pb.d.ts generated/echo_grpc_web_pb.js \\\n      ${tscCompilerOptions} --outDir ./dist`;\n    // this test only makes sure the TS client code compiles successfully\n    runTscCmd(tscCmd);\n\n    // check for the tsc output\n    assertFileExists('./tsc-tests/dist/client06.js');\n    assertFileExists('./tsc-tests/dist/generated/echo_pb.js');\n  });\n});\n"
  },
  {
    "path": "scripts/README.md",
    "content": "# Scripts\n\nA collection of scripts (mostly test related).\n\n\n## Troubleshooting - Bazel Crashes (OOM)\n\n[Bazel](https://github.com/bazelbuild/bazel) can be memory hungry and often\ncrashes while building on Mac with default Docker memory settings (2GB)\n(similar reports: [here](https://github.com/tensorflow/models/issues/3647) and\n[here](https://stackoverflow.com/questions/65605663/cannot-build-with-error-server-terminated-abruptly)).\n\n\nBump the [memory settings](https://docs.docker.com/docker-for-mac/#resources)\nin Docker Desktop for Mac (e.g. to 4 - 6GB) if you see the following errors:\n\n\n```\n$ bazel build //javascript/net/grpc/web/generator/... //net/grpc/gateway/examples/echo/...\n\n...\n\nServer terminated abruptly (error code: 14, error message: 'Socket closed', log file: '/root/.cache/bazel/_bazel_root/.../server/jvm.out')\n\n------\n\nfailed to solve: rpc error: code = Unknown desc = executor failed running [/bin/sh -c bazel build javascript/net/grpc/web/... &&   cp $(bazel info bazel-genfiles)/javascript/net/grpc/web/protoc-gen-grpc-web   /usr/local/bin/protoc-gen-grpc-web]: exit code: 37\n```\n"
  },
  {
    "path": "scripts/docker-run-build-tests.sh",
    "content": "#!/bin/bash\n# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nset -ex\n\n# This script is intended to be run within the base image from\n# net/grpc/gateway/docker/prereqs/Dockerfile\n\n# Ensures all Bazel targets builds\ncd /github/grpc-web && \\\n  bazel clean && \\\n  bazel build \\\n    //javascript/net/grpc/web/generator/... \\\n    //net/grpc/gateway/examples/echo/...\n"
  },
  {
    "path": "scripts/docker-run-interop-tests.sh",
    "content": "#!/bin/bash\n# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nset -ex\n\n# This script is intended to be run within the base image from\n# net/grpc/gateway/docker/prereqs/Dockerfile\n\ncd /github/grpc-web/test/interop && \\\n  npm install && \\\n  npm link grpc-web\n\n# Test grpc-web-text mode\nprotoc -I=../.. src/proto/grpc/testing/test.proto \\\n  src/proto/grpc/testing/empty.proto \\\n  src/proto/grpc/testing/messages.proto \\\n  --js_out=import_style=commonjs:. \\\n  --grpc-web_out=import_style=commonjs,mode=grpcwebtext:. && \\\n  npm test\n\n# Test grpc-web mode (binary)\nprotoc -I=../.. src/proto/grpc/testing/test.proto \\\n  src/proto/grpc/testing/empty.proto \\\n  src/proto/grpc/testing/messages.proto \\\n  --js_out=import_style=commonjs:. \\\n  --grpc-web_out=import_style=commonjs,mode=grpcweb:. && \\\n  npm test -- --mode=binary\n"
  },
  {
    "path": "scripts/docker-run-jsunit-tests.sh",
    "content": "#!/bin/bash\n# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nset -ex\n\n# This script is intended to be run within the base image from\n# packages/grpc-web/docker/jsunit-test/Dockerfile\n\ncd /grpc-web/packages/grpc-web\n\nnpm run test-jsunit\n"
  },
  {
    "path": "scripts/docker-run-mocha-tests.sh",
    "content": "#!/bin/bash\n# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nset -ex\n\n# This script is intended to be run within the base image from\n# net/grpc/gateway/docker/prereqs/Dockerfile\n\ncd /github/grpc-web/packages/grpc-web\nnpm run prepare && \\\n  npm run test-mocha\n"
  },
  {
    "path": "scripts/init_submodules.sh",
    "content": "#!/bin/bash\n# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nset -ex\n\ncd \"$(dirname \"$0\")\"/..\ngit submodule --quiet update --init --recursive\n(cd third_party/protobuf && git checkout tags/v3.15.6)\n"
  },
  {
    "path": "scripts/kokoro.sh",
    "content": "#!/bin/bash\n# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nset -ex\n\nSCRIPT_DIR=$(dirname \"$0\")\ncd \"${SCRIPT_DIR}\"\n\nexport MASTER=1\n\n./run_basic_tests.sh\n\n./run_interop_tests.sh\n"
  },
  {
    "path": "scripts/release_notes.py",
    "content": "# Copyright 2020 gRPC authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"Generate release notes in Markdown from Github PRs.\n\nYou'll need a github API token to avoid being rate-limited. See\nhttps://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/\n\n1. Create a draft release notes / changelog, by running:\n\n$ python3 scripts/release_notes.py --token=<token>  --unreleased_only\n\n2. Adjust each PR, if necessary, after reading the draft:\n\n2a. Apply one of these labels, if you want the PR to be included in the\nrelease notes / changelog:\n\n- release notes: breaking     for breaking changes\n- release notes: major        for major features\n- release notes: yes          for other fixes and changes\n\n2b. Fix any PR title, to better reflect the changes done.\n\n2c. Add \"author:@<github username>\" to the PR body to attribute the code to\nthe original author if this is an import/export.\n\n3. Finalize the release notes, by running:\n\n$ python3 scripts/release_notes.py --token=<token> > CHANGELOG.md\n\n4. Check in the changes.\n\n\"\"\"\n\nfrom collections import defaultdict\nimport urllib\nfrom urllib.request import Request, urlopen\nfrom enum import Enum\nimport json\nimport re\nimport subprocess\n\nAPI_BASE_URL = \"https://api.github.com/repos/grpc/grpc-web\"\nGRPC_WEB_TEAM = [\n    \"stanley-cheung\",\n    \"sampajano\",\n    \"fengli79\",\n    \"vnorigoog\",\n    \"wenbozhu\",\n    \"jtattermusch\",\n    \"srini100\",\n    \"hsaliak\",\n]\nUNRELEASED = 'Unreleased'\n\nclass LabelLevel(Enum):\n    NO_LABEL = 0\n    WITH_LABEL = 1       # release notes: yes\n    MAJOR_FEATURE = 2    # release notes: major\n    BREAKING_CHANGE = 3  # release notes: breaking\n    def __gt__(self, other):\n        if self.__class__ is other.__class__:\n            return self.value > other.value\n        return NotImplemented\n    def __lt__(self, other):\n        if self.__class__ is other.__class__:\n            return self.value < other.value\n        return NotImplemented\n\n# Represent the changelog of one release\nclass ReleaseNotes:\n    def __init__(self):\n        self.without_labels = []\n        self.with_labels = []\n        self.major_features = []\n        self.breaking_changes = []\n\n# Main operations\nclass ProcessChangelog:\n    def __init__(self):\n        self.token = \"\"\n        self.releases = []\n        self.merged_prs = []\n        self.changelog_by_release = defaultdict(ReleaseNotes)\n        # When True, only gather and output the Unreleased section and\n        # stop querying older PR pages as soon as we encounter the first\n        # PR that belongs to a released tag.\n        self.unreleased_only = False\n\n    # Make a Github API call\n    def github_api(self, url):\n        if not url.startswith('http'):\n            url = API_BASE_URL + url\n        req = Request(url)\n        req.add_header('Authorization', 'token {}'.format(self.token))\n        f = urlopen(req)\n        response = json.loads(f.read().decode('utf-8'))\n        return response, f.info()\n\n    # Find out which release a PR belongs to\n    def check_release(self, sha):\n        for release in self.releases:\n            retcode = subprocess.call([\n                \"git\", \"merge-base\", \"--is-ancestor\", sha, release['sha']\n            ])\n            if retcode == 0:\n                return release['release']\n        return UNRELEASED\n\n    # A helper function to check through all the \"release notes: xxx\"\n    # labels of a PR and return the highest level\n    def _get_pr_label_level(self, labels):\n        label_level = LabelLevel.NO_LABEL\n        for label in labels:\n            _label_level = LabelLevel.NO_LABEL\n            if label['name'] == \"release notes: yes\":\n                _label_level = LabelLevel.WITH_LABEL\n            elif label['name'] == \"release notes: major\":\n                _label_level = LabelLevel.MAJOR_FEATURE\n            elif label['name'] == \"release notes: breaking\":\n                _label_level = LabelLevel.BREAKING_CHANGE\n            if _label_level > label_level: # retain the highest level\n                label_level = _label_level\n        return label_level\n\n    # Retrieve the list of all the releases\n    def get_releases(self):\n        if self.unreleased_only:\n            # Optimization: only need the latest release to detect boundary\n            latest_release, _ = self.github_api('/releases/latest')\n            ref_data, _ = self.github_api('/git/ref/tags/' + latest_release['tag_name'])\n            tag_data, _ = self.github_api('/git/commits/' + ref_data['object']['sha'])\n            self.releases.append({\n                'release': latest_release['tag_name'],\n                'date': tag_data['author']['date'],\n                'sha': ref_data['object']['sha'][0:7]\n            })\n        else:\n            # Might get into trouble if we ever have more than 30 releases\n            github_releases, _ = self.github_api('/releases')\n            for release in github_releases:\n                ref_data, _ = self.github_api('/git/ref/tags/' + release['tag_name'])\n                tag_data, _ = self.github_api('/git/commits/' + ref_data['object']['sha'])\n                self.releases.append({\n                    'release': release['tag_name'],\n                    'date': tag_data['author']['date'],\n                    'sha': ref_data['object']['sha'][0:7]\n                })\n            self.releases.sort(key=lambda val:val['date'])\n\n    # Retrieve the list of all merged PRs\n    def get_merged_prs(self, num_pages):\n        url = '/pulls?state=closed'\n        while True:\n            response, headers = self.github_api(url)\n            for pr in response:\n                if pr['number'] == 1: # had trouble with git merge-base\n                    continue\n                if pr['merged_at'] is None: # not merged\n                    continue\n                label_level = self._get_pr_label_level(pr['labels'])\n                m = None if pr['body'] is None else re.search(\n                    r'author: ?@([A-Za-z\\d-]+)', pr['body'])\n                if m:\n                    author = m[1] # author attribution override\n                else:\n                    author = pr['user']['login']\n                sha = pr['merge_commit_sha'][0:7]\n                release = self.check_release(sha)\n                self.merged_prs.append({\n                    'number': str(pr['number']),\n                    'author': author,\n                    'title': pr['title'],\n                    'release': release,\n                    'label_level': label_level,\n                })\n\n                # Optimization: if only unreleased requested and we hit\n                # a PR that's already part of a released tag, we can\n                # stop. The API returns PRs in reverse chronological\n                # order, so older ones will also be released.\n                if self.unreleased_only and release != UNRELEASED:\n                    return\n\n            num_pages -= 1\n            if num_pages == 0:\n                break\n\n            link = headers.get('link')\n            if re.search(r'; rel=\"next\"', link):\n                # next page\n                url = re.sub(r'.*<(.*)>; rel=\"next\".*', r'\\1', link)\n            else:\n                break\n\n    # Format each PR into one line of release notes, and classify them\n    # by release and label level\n    def format_release_notes(self):\n        for pr in self.merged_prs:\n            release = pr['release']\n            author = pr['author']\n            num = '[#{}](https://github.com/grpc/grpc-web/pull/{})'.format(\n                pr['number'], pr['number'])\n            if len(pr['title']) > 70:\n                title = pr['title'][0:70] + \"...\"\n            else:\n                title = pr['title']\n            if author not in GRPC_WEB_TEAM:\n                credit = f\" @{author}\"\n            else:\n                credit = \"\"\n\n            final_formatted_line = \"- {} {}{}\".format(num, title, credit)\n\n            release_notes = self.changelog_by_release[release]\n            if pr['label_level'] == LabelLevel.BREAKING_CHANGE:\n                release_notes.breaking_changes.append(final_formatted_line)\n            elif pr['label_level'] == LabelLevel.MAJOR_FEATURE:\n                release_notes.major_features.append(final_formatted_line)\n            elif pr['label_level'] == LabelLevel.WITH_LABEL:\n                release_notes.with_labels.append(final_formatted_line)\n            else:\n                release_notes.without_labels.append(final_formatted_line)\n\n    # Print the final result in the form of CHANGELOG.md\n    def print_changelog(self, output_without_labels, output_unreleased_only):\n        print(\"[//]: # (GENERATED FILE -- DO NOT EDIT!)\")\n        print(\"[//]: # (See scripts/release_notes.py for more details.)\")\n        for release, release_notes in self.changelog_by_release.items():\n            # Always include Unreleased unless we're filtering to only\n            # unreleased (handled by the check below).\n            if output_unreleased_only and release != UNRELEASED:\n                continue\n            print_other_changes_heading = False\n            print(\"\")\n            print(\"## {}\".format(release))\n            if release_notes.breaking_changes:\n                print_other_changes_heading = True\n                print(\"\")\n                print(\"### Breaking Changes\")\n                print(\"\")\n                for line in release_notes.breaking_changes:\n                    print(line)\n            if release_notes.major_features:\n                print_other_changes_heading = True\n                print(\"\")\n                print(\"### Major Features\")\n                print(\"\")\n                for line in release_notes.major_features:\n                    print(line)\n            if release_notes.with_labels:\n                print(\"\")\n                if print_other_changes_heading:\n                    print(\"### Other Changes\")\n                    print(\"\")\n                for line in release_notes.with_labels:\n                    print(line)\n            if release_notes.without_labels and output_without_labels:\n                print(\"\")\n                print(\"### Without Labels\")\n                print(\"\")\n                for line in release_notes.without_labels:\n                    print(line)\n            print(\"\")\n\ndef build_args_parser():\n    import argparse\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--token',\n                        type=str,\n                        default='',\n                        help='Github API token')\n    parser.add_argument('--num_pages',\n                        type=int,\n                        default=20,\n                        help='Number of pages to go back')\n    parser.add_argument('--output_without_labels',\n                        default=False,\n                        action='store_true',\n                        help='Whether to output PRs without labels')\n    parser.add_argument('--unreleased_only',\n                        default=False,\n                        action='store_true',\n                        help='Only output the Unreleased section (Including PRs without labels)')\n    return parser\n\ndef main():\n    parser = build_args_parser()\n    args = parser.parse_args()\n    token, num_pages = args.token, args.num_pages\n    unreleased_only = args.unreleased_only\n    # If --unreleased_only is set, we implicitly enable without-labels output.\n    output_without_labels = args.output_without_labels or unreleased_only\n    if token == \"\":\n        print(\"Error: Github API token is required --token=<token>\")\n        return\n\n    worker = ProcessChangelog()\n    worker.token = token\n    worker.unreleased_only = unreleased_only\n\n    # Retrieve the list of all the releases (optimized when unreleased_only)\n    worker.get_releases()\n\n    # Retrieve the list of all merged PRs\n    worker.get_merged_prs(num_pages)\n\n    # Format each PR into one line of release notes, and classify them\n    # by release and label level\n    worker.format_release_notes()\n\n    # Print the final result in the form of CHANGELOG.md\n    worker.print_changelog(output_without_labels, unreleased_only)\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/run_basic_tests.sh",
    "content": "#!/bin/bash\n# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nset -ex\n\nSCRIPT_DIR=$(dirname \"$0\")\nREPO_DIR=$(realpath \"${SCRIPT_DIR}/..\")\n\n# Set up\ncd \"${REPO_DIR}\"\n\n\n# These programs need to be already installed\nprogs=(docker docker-compose curl)\nfor p in \"${progs[@]}\"\ndo\n  command -v \"$p\" > /dev/null 2>&1 || \\\n    { echo >&2 \"$p is required but not installed. Aborting.\"; exit 1; }\ndone\n\n##########################################################\n# Step 1: Run all unit tests\n##########################################################\necho -e \"\\n[Running] Basic test #1 - Runnning unit tests\"\n# Run jsunit tests\ndocker-compose build jsunit-test\ndocker run --rm grpcweb/jsunit-test /bin/bash \\\n    /grpc-web/scripts/docker-run-jsunit-tests.sh\n\n# Run (mocha) unit tests\ndocker-compose build prereqs\ndocker run --rm grpcweb/prereqs /bin/bash \\\n  /github/grpc-web/scripts/docker-run-mocha-tests.sh\n\n\n##########################################################\n# Step 2: Test echo server\n##########################################################\necho -e \"\\n[Running] Basic test #2 - Testing echo server\"\ndocker-compose build prereqs envoy node-server\n\n# Bring up the Echo server and the Envoy proxy (in background).\n# The 'sleep' seems necessary for the docker containers to be fully up\n# and listening before we test the with curl requests\ndocker-compose up -d node-server envoy && sleep 5;\n\n# Run a curl request and verify the output\nsource ./scripts/test-proxy.sh\n\n# Remove all docker containers\ndocker-compose down\n\n\n##########################################################\n# Step 3: Test all Dockerfile and Bazel targets can build!\n##########################################################\necho -e \"\\n[Running] Basic test #3 - Testing everything buids\"\nif [[ \"$MASTER\" == \"1\" ]]; then\n  # Build all for continuous_integration\n  docker-compose build\nelse\n  # Only build a subset of docker images for presubmit runs\n  docker-compose build commonjs-client closure-client ts-client\nfi\n\n# Run build tests to ensure all Bazel targets can build.\ndocker run --rm grpcweb/prereqs /bin/bash \\\n  /github/grpc-web/scripts/docker-run-build-tests.sh\n\n# Clean up\ngit clean -f -d -x\necho 'Basic tests completed successfully!'\n"
  },
  {
    "path": "scripts/run_interop_tests.sh",
    "content": "#!/bin/bash\n# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nset -ex\n\nrun_tests () {\n  docker run --network=host --rm grpcweb/prereqs /bin/bash \\\n    /github/grpc-web/scripts/docker-run-interop-tests.sh\n}\n\nSCRIPT_DIR=$(dirname \"$0\")\nREPO_DIR=$(realpath \"${SCRIPT_DIR}/..\")\n\n# Set up\ncd \"${REPO_DIR}\"\n\n# These programs need to be already installed\nprogs=(docker docker-compose npm)\nfor p in \"${progs[@]}\"\ndo\n  command -v \"$p\" > /dev/null 2>&1 || \\\n    { echo >&2 \"$p is required but not installed. Aborting.\"; exit 1; }\ndone\n\nfunction cleanup () {\n  echo \"Killing lingering Docker servers...\"\n  docker rm -f \"$pid1\"\n  docker rm -f \"$pid2\"\n}\n\ntrap cleanup EXIT\n\n# Build all relevant docker images. They should all build successfully.\ndocker-compose build prereqs node-interop-server\n\n##########################################################\n# Run interop tests (against Envoy)\n##########################################################\necho -e \"\\n[Running] Interop test (Envoy)\"\npid1=$(docker run -d \\\n  -v \"$(pwd)\"/test/interop/envoy.yaml:/etc/envoy/envoy.yaml:ro \\\n  --network=host envoyproxy/envoy:v1.22.0)\npid2=$(docker run -d --network=host grpcweb/node-interop-server)\n\nrun_tests\n\ndocker rm -f \"$pid1\"\ndocker rm -f \"$pid2\""
  },
  {
    "path": "scripts/test-proxy.sh",
    "content": "#!/bin/bash\n# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nset -ex\n\n# Run a curl request to test the output of the proxy and the backend server.\n# This is a simple unary call with \"hello\" as the protobuf message\nout=$(curl -s 'http://localhost:8080/grpc.gateway.testing.EchoService/Echo' \\\n  -H 'Content-Type: application/grpc-web-text' \\\n  -H 'Accept: application/grpc-web-text' \\\n  -H 'Connection: keep-alive' \\\n  -H 'X-Grpc-Web: 1' \\\n  -H 'X-User-Agent: grpc-web-javascript/0.1' \\\n  --data-binary 'AAAAAAcKBWhlbGxv')\n\n# Cut out a few parts of the response that we are reasonably sure that should\n# not change.\n#\n# Take the first 13 bytes:\n#   First byte: 00 (data marker)\n#   Next 4 bytes: 00 00 00 07 (length of payload)\n#   Next 7 bytes: 0a 05 68 65 6c 6c 6f (binary proto of \"1: hello\")\n#   Next 1 byte: 80 (trailer marker)\n# Skip the next 4 bytes:\n#   This represents the length of the trailer frame, which could be unreliable.\n# Take the next 15 bytes:\n#   This is the beginning of the trailer frame, which we are reasonably sure\n#   that it will begin with:\n#     grpc-status:0\\r\\n\ns1=$(echo \"$out\" | base64 -d | \\\n  { dd bs=1 count=13 ; dd skip=4 bs=1 count=15 ; } 2>/dev/null | \\\n  base64)\n\necho \"$s1\" | base64 -d | xxd\n\n# Take the 28 bytes we cut out above, the base64-encoded string should be this\nif [[ \"$s1\" != \"AAAAAAcKBWhlbGxvgGdycGMtc3RhdHVzOjANCg==\" ]]; then\n  exit 1;\nelse\n  echo \"Envoy proxy test successful!\"\nfi\n"
  },
  {
    "path": "src/proto/grpc/testing/empty.proto",
    "content": "\n// Copyright 2015 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage grpc.testing;\n\n// An empty message that you can re-use to avoid defining duplicated empty\n// messages in your project. A typical example is to use it as argument or the\n// return value of a service API. For instance:\n//\n//   service Foo {\n//     rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };\n//   };\n//\nmessage Empty {}\n"
  },
  {
    "path": "src/proto/grpc/testing/messages.proto",
    "content": "\n// Copyright 2015-2016 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Message definitions to be used by integration test service definitions.\n\nsyntax = \"proto3\";\n\npackage grpc.testing;\n\n// TODO(dgq): Go back to using well-known types once\n// https://github.com/grpc/grpc/issues/6980 has been fixed.\n// import \"google/protobuf/wrappers.proto\";\nmessage BoolValue {\n  // The bool value.\n  bool value = 1;\n}\n\n// The type of payload that should be returned.\nenum PayloadType {\n  // Compressable text format.\n  COMPRESSABLE = 0;\n}\n\n// A block of data, to simply increase gRPC message size.\nmessage Payload {\n  // The type of data in body.\n  PayloadType type = 1;\n  // Primary contents of payload.\n  bytes body = 2;\n}\n\n// A protobuf representation for grpc status. This is used by test\n// clients to specify a status that the server should attempt to return.\nmessage EchoStatus {\n  int32 code = 1;\n  string message = 2;\n}\n\n// The type of route that a client took to reach a server w.r.t. gRPCLB.\n// The server must fill in \"fallback\" if it detects that the RPC reached\n// the server via the \"gRPCLB fallback\" path, and \"backend\" if it detects\n// that the RPC reached the server via \"gRPCLB backend\" path (i.e. if it got\n// the address of this server from the gRPCLB server BalanceLoad RPC). Exactly\n// how this detection is done is context and server dependent.\nenum GrpclbRouteType {\n  // Server didn't detect the route that a client took to reach it.\n  GRPCLB_ROUTE_TYPE_UNKNOWN = 0;\n  // Indicates that a client reached a server via gRPCLB fallback.\n  GRPCLB_ROUTE_TYPE_FALLBACK = 1;\n  // Indicates that a client reached a server as a gRPCLB-given backend.\n  GRPCLB_ROUTE_TYPE_BACKEND = 2;\n}\n\n// Unary request.\nmessage SimpleRequest {\n  // Desired payload type in the response from the server.\n  // If response_type is RANDOM, server randomly chooses one from other formats.\n  PayloadType response_type = 1;\n\n  // Desired payload size in the response from the server.\n  int32 response_size = 2;\n\n  // Optional input payload sent along with the request.\n  Payload payload = 3;\n\n  // Whether SimpleResponse should include username.\n  bool fill_username = 4;\n\n  // Whether SimpleResponse should include OAuth scope.\n  bool fill_oauth_scope = 5;\n\n  // Whether to request the server to compress the response. This field is\n  // \"nullable\" in order to interoperate seamlessly with clients not able to\n  // implement the full compression tests by introspecting the call to verify\n  // the response's compression status.\n  BoolValue response_compressed = 6;\n\n  // Whether server should return a given status\n  EchoStatus response_status = 7;\n\n  // Whether the server should expect this request to be compressed.\n  BoolValue expect_compressed = 8;\n\n  // Whether SimpleResponse should include server_id.\n  bool fill_server_id = 9;\n\n  // Whether SimpleResponse should include grpclb_route_type.\n  bool fill_grpclb_route_type = 10;\n}\n\n// Unary response, as configured by the request.\nmessage SimpleResponse {\n  // Payload to increase message size.\n  Payload payload = 1;\n  // The user the request came from, for verifying authentication was\n  // successful when the client expected it.\n  string username = 2;\n  // OAuth scope.\n  string oauth_scope = 3;\n\n  // Server ID. This must be unique among different server instances,\n  // but the same across all RPC's made to a particular server instance.\n  string server_id = 4;\n  // gRPCLB Path.\n  GrpclbRouteType grpclb_route_type = 5;\n\n  // Server hostname.\n  string hostname = 6;\n}\n\n// Client-streaming request.\nmessage StreamingInputCallRequest {\n  // Optional input payload sent along with the request.\n  Payload payload = 1;\n\n  // Whether the server should expect this request to be compressed. This field\n  // is \"nullable\" in order to interoperate seamlessly with servers not able to\n  // implement the full compression tests by introspecting the call to verify\n  // the request's compression status.\n  BoolValue expect_compressed = 2;\n\n  // Not expecting any payload from the response.\n}\n\n// Client-streaming response.\nmessage StreamingInputCallResponse {\n  // Aggregated size of payloads received from the client.\n  int32 aggregated_payload_size = 1;\n}\n\n// Configuration for a particular response.\nmessage ResponseParameters {\n  // Desired payload sizes in responses from the server.\n  int32 size = 1;\n\n  // Desired interval between consecutive responses in the response stream in\n  // microseconds.\n  int32 interval_us = 2;\n\n  // Whether to request the server to compress the response. This field is\n  // \"nullable\" in order to interoperate seamlessly with clients not able to\n  // implement the full compression tests by introspecting the call to verify\n  // the response's compression status.\n  BoolValue compressed = 3;\n}\n\n// Server-streaming request.\nmessage StreamingOutputCallRequest {\n  // Desired payload type in the response from the server.\n  // If response_type is RANDOM, the payload from each response in the stream\n  // might be of different types. This is to simulate a mixed type of payload\n  // stream.\n  PayloadType response_type = 1;\n\n  // Configuration for each expected response message.\n  repeated ResponseParameters response_parameters = 2;\n\n  // Optional input payload sent along with the request.\n  Payload payload = 3;\n\n  // Whether server should return a given status\n  EchoStatus response_status = 7;\n}\n\n// Server-streaming response, as configured by the request and parameters.\nmessage StreamingOutputCallResponse {\n  // Payload to increase response size.\n  Payload payload = 1;\n}\n\n// For reconnect interop test only.\n// Client tells server what reconnection parameters it used.\nmessage ReconnectParams {\n  int32 max_reconnect_backoff_ms = 1;\n}\n\n// For reconnect interop test only.\n// Server tells client whether its reconnects are following the spec and the\n// reconnect backoffs it saw.\nmessage ReconnectInfo {\n  bool passed = 1;\n  repeated int32 backoff_ms = 2;\n}\n\nmessage LoadBalancerStatsRequest {\n  // Request stats for the next num_rpcs sent by client.\n  int32 num_rpcs = 1;\n  // If num_rpcs have not completed within timeout_sec, return partial results.\n  int32 timeout_sec = 2;\n}\n\nmessage LoadBalancerStatsResponse {\n  // The number of completed RPCs for each peer.\n  map<string, int32> rpcs_by_peer = 1;\n  // The number of RPCs that failed to record a remote peer.\n  int32 num_failures = 2;\n}\n"
  },
  {
    "path": "src/proto/grpc/testing/test.proto",
    "content": "\n// Copyright 2015-2016 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// An integration test service that covers all the method signature permutations\n// of unary/streaming requests/responses.\n\nsyntax = \"proto3\";\n\nimport \"src/proto/grpc/testing/empty.proto\";\nimport \"src/proto/grpc/testing/messages.proto\";\n\npackage grpc.testing;\n\n// A simple service to test the various types of RPCs and experiment with\n// performance with various types of payload.\nservice TestService {\n  // One empty request followed by one empty response.\n  rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);\n\n  // One request followed by one response.\n  rpc UnaryCall(SimpleRequest) returns (SimpleResponse);\n\n  // One request followed by one response. Response has cache control\n  // headers set such that a caching HTTP proxy (such as GFE) can\n  // satisfy subsequent requests.\n  rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse);\n\n  // One request followed by a sequence of responses (streamed download).\n  // The server returns the payload with client desired type and sizes.\n  rpc StreamingOutputCall(StreamingOutputCallRequest)\n      returns (stream StreamingOutputCallResponse);\n\n  // A sequence of requests followed by one response (streamed upload).\n  // The server returns the aggregated size of client payload as the result.\n  rpc StreamingInputCall(stream StreamingInputCallRequest)\n      returns (StreamingInputCallResponse);\n\n  // A sequence of requests with each request served by the server immediately.\n  // As one request could lead to multiple responses, this interface\n  // demonstrates the idea of full duplexing.\n  rpc FullDuplexCall(stream StreamingOutputCallRequest)\n      returns (stream StreamingOutputCallResponse);\n\n  // A sequence of requests followed by a sequence of responses.\n  // The server buffers all the client requests and then serves them in order. A\n  // stream of responses are returned to the client when the server starts with\n  // first request.\n  rpc HalfDuplexCall(stream StreamingOutputCallRequest)\n      returns (stream StreamingOutputCallResponse);\n\n  // The test server will not implement this method. It will be used\n  // to test the behavior when clients call unimplemented methods.\n  rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty);\n}\n\n// A simple service NOT implemented at servers so clients can test for\n// that case.\nservice UnimplementedService {\n  // A call that no server should implement\n  rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty);\n}\n\n// A service used to control reconnect server.\nservice ReconnectService {\n  rpc Start(grpc.testing.ReconnectParams) returns (grpc.testing.Empty);\n  rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo);\n}\n\n// A service used to obtain stats for verifying LB behavior.\nservice LoadBalancerStatsService {\n  // Gets the backend distribution for RPCs sent by a test client.\n  rpc GetClientStats(LoadBalancerStatsRequest)\n      returns (LoadBalancerStatsResponse) {}\n}\n"
  },
  {
    "path": "test/interop/.gitignore",
    "content": "node_modules/\npackage-lock.json\nsrc/\n"
  },
  {
    "path": "test/interop/README.md",
    "content": "gRPC-Web Interop Tests\n======================\n\nSee the\n[main doc](https://github.com/grpc/grpc-web/blob/master/doc/interop-test-descriptions.md)\nfor details about gRPC interop tests in general and the list of test cases.\n\n\nRun interop tests\n-----------------\n\n### Build some docker images\n\n```sh\n$ cd grpc-web\n$ docker-compose build prereqs node-interop-server interop-client\n```\n\n\n### Run the Node interop server\n\nAn interop server implemented in Node is hosted in the `grpc/grpc-node` repo.\n\n```sh\n$ docker run -d --network=host grpcweb/node-interop-server\n```\n\n\n### Run the Envoy proxy\n\nAn `envoy.yaml` file is provided in this directory to direct traffic for these\ntests.\n\n```sh\n$ docker run -d -v $(pwd)/test/interop/envoy.yaml:/etc/envoy/envoy.yaml:ro \\\n  --network=host envoyproxy/envoy:v1.22.0\n```\n\n\n### Run the gRPC-Web browser client\n\nYou can either run the interop client as `npm test`, like this:\n\n```sh\n$ docker run --network=host --rm grpcweb/prereqs /bin/bash \\\n  /github/grpc-web/scripts/docker-run-interop-tests.sh\n```\n\nOr from the browser:\n\n```sh\n$ docker-compose up interop-client\n```\n\nOpen up the browser and go to `http://localhost:8081/index.html` and open up\nthe console.\n"
  },
  {
    "path": "test/interop/envoy.yaml",
    "content": "admin:\n  access_log_path: /tmp/admin_access.log\n  address:\n    socket_address: { address: 0.0.0.0, port_value: 9901 }\n\nstatic_resources:\n  listeners:\n    - name: listener_0\n      address:\n        socket_address: { address: 0.0.0.0, port_value: 8080 }\n      filter_chains:\n        - filters:\n          - name: envoy.filters.network.http_connection_manager\n            typed_config:\n              \"@type\": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager\n              codec_type: auto\n              stat_prefix: ingress_http\n              route_config:\n                name: local_route\n                virtual_hosts:\n                  - name: local_service\n                    domains: [\"*\"]\n                    routes:\n                      - match: { prefix: \"/\" }\n                        route:\n                          cluster: interop_service\n                          timeout: 0s\n                          max_stream_duration:\n                            grpc_timeout_header_max: 0s\n                    cors:\n                      allow_origin_string_match:\n                        - prefix: \"*\"\n                      allow_methods: GET, PUT, DELETE, POST, OPTIONS\n                      allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,x-grpc-test-echo-initial,x-grpc-test-echo-trailing-bin,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout\n                      max_age: \"1728000\"\n                      expose_headers: x-grpc-test-echo-initial,x-grpc-test-echo-trailing-bin,grpc-status,grpc-message\n              http_filters:\n                - name: envoy.filters.http.grpc_web\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb\n                - name: envoy.filters.http.cors\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors\n                - name: envoy.filters.http.router\n                  typed_config:\n                    \"@type\": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router\n  clusters:\n    - name: interop_service\n      connect_timeout: 0.25s\n      type: logical_dns\n      # HTTP/2 support\n      typed_extension_protocol_options:\n        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:\n          \"@type\": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions\n          explicit_http_config:\n            http2_protocol_options: {}\n      lb_policy: round_robin\n      load_assignment:\n        cluster_name: cluster_0\n        endpoints:\n          - lb_endpoints:\n            - endpoint:\n                address:\n                  socket_address:\n                    address: localhost\n                    port_value: 7074\n"
  },
  {
    "path": "test/interop/index.html",
    "content": "<!-- Copyright 2018 Google LLC  -->\n\n<!-- Licensed under the Apache License, Version 2.0 (the \"License\");  -->\n<!-- you may not use this file except in compliance with the License.  -->\n<!-- You may obtain a copy of the License at  -->\n\n<!--     https://www.apache.org/licenses/LICENSE-2.0  -->\n\n<!-- Unless required by applicable law or agreed to in writing, software  -->\n<!-- distributed under the License is distributed on an \"AS IS\" BASIS,  -->\n<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  -->\n<!-- See the License for the specific language governing permissions and  -->\n<!-- limitations under the License.  -->\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>Interop Test</title>\n<link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\">\n<script src=\"//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>\n<script src=\"./dist/main.js\"></script>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"row\" id=\"first\">\n      <p>Please open up the console to see the test results.</p>\n    </div>\n  </div>\n</body>\n</html>\n"
  },
  {
    "path": "test/interop/interop_client.js",
    "content": "/**\n *\n * Copyright 2018 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nconst {Empty} = require('./src/proto/grpc/testing/empty_pb.js');\nconst {SimpleRequest,\n       StreamingOutputCallRequest,\n       EchoStatus,\n       Payload,\n       ResponseParameters} =\n         require('./src/proto/grpc/testing/messages_pb.js');\nconst {TestServiceClient} =\n  require('./src/proto/grpc/testing/test_grpc_web_pb.js');\nvar assert = require('assert');\nconst grpc = {};\ngrpc.web = require('grpc-web');\n\nconst SERVER_HOST = 'http://localhost:8080';\nconst TIMEOUT_MS = 1000; // 1 second\n\nfunction multiDone(done, count) {\n  return function() {\n    count -= 1;\n    if (count <= 0) {\n      done();\n    }\n  };\n}\n\nfunction doEmptyUnary(done) {\n  var testService = new TestServiceClient(SERVER_HOST, null, null);\n  testService.emptyCall(new Empty(), null, (err, response) => {\n    assert.ifError(err);\n    assert(response instanceof Empty);\n    done();\n  });\n}\n\nfunction doEmptyUnaryWithDeadline(done) {\n  var testService = new TestServiceClient(SERVER_HOST, null, null);\n\n  const deadline = new Date();\n  deadline.setSeconds(deadline.getSeconds() + 1);\n  testService.emptyCall(new Empty(), {deadline: deadline.getTime().toString()},\n    (err, response) => {\n      assert.ifError(err);\n      assert(response instanceof Empty);\n      done();\n    });\n}\n\nfunction doLargeUnary(done) {\n  var testService = new TestServiceClient(SERVER_HOST, null, null);\n  var req = new SimpleRequest();\n  var size = 314159;\n\n  var payload = new Payload();\n  payload.setBody('0'.repeat(271828));\n\n  req.setPayload(payload);\n  req.setResponseSize(size);\n\n  testService.unaryCall(req, null, (err, response) => {\n    assert.ifError(err);\n    assert.equal(response.getPayload().getBody().length, size);\n    done();\n  });\n}\n\nfunction doServerStreaming(done) {\n  var testService = new TestServiceClient(SERVER_HOST, null, null);\n  var sizes = [31415, 9, 2653, 58979];\n\n  var responseParams = sizes.map((size, idx) => {\n    var param = new ResponseParameters();\n    param.setSize(size);\n    param.setIntervalUs(idx * 10);\n    return param;\n  });\n\n  var req = new StreamingOutputCallRequest();\n  req.setResponseParametersList(responseParams);\n\n  var stream = testService.streamingOutputCall(req);\n\n  done = multiDone(done, sizes.length);\n  var numCallbacks = 0;\n  stream.on('data', (response) => {\n    assert.equal(response.getPayload().getBody().length, sizes[numCallbacks]);\n    numCallbacks++;\n    done();\n  });\n}\n\nfunction doCustomMetadata(done) {\n  var testService = new TestServiceClient(SERVER_HOST, null, null);\n  done = multiDone(done, 3);\n\n  var req = new SimpleRequest();\n  const size = 314159;\n  const ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';\n  const ECHO_INITIAL_VALUE = 'test_initial_metadata_value';\n  const ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';\n  const ECHO_TRAILING_VALUE = 0xababab;\n\n  var payload = new Payload();\n  payload.setBody('0'.repeat(271828));\n\n  req.setPayload(payload);\n  req.setResponseSize(size);\n\n  var call = testService.unaryCall(req, {\n    [ECHO_INITIAL_KEY]: ECHO_INITIAL_VALUE,\n    [ECHO_TRAILING_KEY]: ECHO_TRAILING_VALUE\n  }, (err, response) => {\n    assert.ifError(err);\n    assert.equal(response.getPayload().getBody().length, size);\n    done();\n  });\n\n  call.on('metadata', (metadata) => {\n    assert(ECHO_INITIAL_KEY in metadata);\n    assert.equal(metadata[ECHO_INITIAL_KEY], ECHO_INITIAL_VALUE);\n    done();\n  });\n\n  call.on('status', (status) => {\n    assert('metadata' in status);\n    assert(ECHO_TRAILING_KEY in status.metadata);\n    assert.equal(status.metadata[ECHO_TRAILING_KEY], ECHO_TRAILING_VALUE);\n    done();\n  });\n}\n\nfunction doStatusCodeAndMessage(done) {\n  var testService = new TestServiceClient(SERVER_HOST, null, null);\n  var req = new SimpleRequest();\n\n  const TEST_STATUS_MESSAGE = 'test status message';\n  const echoStatus = new EchoStatus();\n  echoStatus.setCode(2);\n  echoStatus.setMessage(TEST_STATUS_MESSAGE);\n\n  req.setResponseStatus(echoStatus);\n\n  testService.unaryCall(req, {}, (err, response) => {\n    assert(err);\n    assert('code' in err);\n    assert('message' in err);\n    assert.equal(err.code, 2);\n    assert.equal(err.message, TEST_STATUS_MESSAGE);\n    done();\n  });\n}\n\nfunction doUnimplementedMethod(done) {\n  var testService = new TestServiceClient(SERVER_HOST, null, null);\n  testService.unimplementedCall(new Empty(), {}, (err, response) => {\n    assert(err);\n    assert('code' in err);\n    assert.equal(err.code, 12);\n    done();\n  });\n}\n\n\nvar testCases = {\n  'empty_unary': {testFunc: doEmptyUnary},\n  'empty_unary_with_deadline': {testFunc: doEmptyUnaryWithDeadline},\n  'large_unary': {testFunc: doLargeUnary},\n  'server_streaming': {testFunc: doServerStreaming,\n                       skipBinaryMode: true},\n  'custom_metadata': {testFunc: doCustomMetadata},\n  'status_code_and_message': {testFunc: doStatusCodeAndMessage},\n  'unimplemented_method': {testFunc: doUnimplementedMethod}\n};\n\nif (typeof window === 'undefined') { // Running from Node\n  console.log('Running from Node...');\n\n  // Fill in XHR runtime\n  global.XMLHttpRequest = require(\"xhr2\");\n\n  var parseArgs = require('minimist');\n  var argv = parseArgs(process.argv, {\n    string: ['mode']\n  });\n  if (argv.mode == 'binary') {\n    console.log('Testing grpc-web mode (binary)...');\n  } else {\n    console.log('Testing grpc-web-text mode...');\n  }\n\n  describe('grpc-web interop tests', function() {\n    Object.keys(testCases).forEach((testCase) => {\n      if (argv.mode == 'binary' && testCases[testCase].skipBinaryMode) return;\n      it('should pass '+testCase, testCases[testCase].testFunc)\n        .timeout(TIMEOUT_MS);\n    });\n  });\n} else {\n  console.log('Running from browser...');\n\n  Object.keys(testCases).forEach((testCase) => {\n    var testFunc = testCases[testCase].testFunc;\n\n    var doneCalled = false;\n    testFunc((err) => {\n      if (err) {\n        throw err;\n      } else {\n        doneCalled = true;\n        console.log(testCase+': passed');\n      }\n    });\n\n    setTimeout(() => {\n      if (!doneCalled) {\n        throw testCase+': failed. Not all done() are called';\n      }\n    }, TIMEOUT_MS);\n  });\n}\n"
  },
  {
    "path": "test/interop/package.json",
    "content": "{\n  \"name\": \"grpc-web-interop-test\",\n  \"version\": \"0.1.0\",\n  \"description\": \"gRPC-Web Interop Test Client\",\n  \"license\": \"Apache-2.0\",\n  \"scripts\": {\n    \"test\": \"mocha -b interop_client.js\"\n  },\n  \"dependencies\": {\n    \"google-protobuf\": \"~3.21.4\",\n    \"grpc-web\": \"~2.0.2\"\n  },\n  \"devDependencies\": {\n    \"assert\": \"^2.0.0\",\n    \"minimist\": \"~1.2.5\",\n    \"mocha\": \"~7.1.1\",\n    \"webpack\": \"5.101.3\",\n    \"webpack-cli\": \"~5.1.1\",\n    \"xhr2\": \"~0.2.0\"\n  }\n}\n"
  },
  {
    "path": "test/interop/webpack.config.js",
    "content": "module.exports = {\n  mode: \"production\",\n  entry: \"./interop_client.js\",\n};\n"
  }
]