[
  {
    "path": ".dockerignore",
    "content": "/admin/.env\n/admin/.next\n/admin/dist\n/admin/node_modules\n/dist\n/docs\n/hetty\n/cmd/hetty/admin"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: dstotijn\npatreon: dstotijn\ncustom: \"https://www.paypal.com/paypalme/dstotijn\"\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Smartphone (please complete the following information):**\n - Device: [e.g. iPhone6]\n - OS: [e.g. iOS8.1]\n - Browser [e.g. stock browser, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Ask a question\n    url: https://github.com/dstotijn/hetty/discussions\n    about: Ask questions and discuss with other community members\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/build-test.yml",
    "content": "name: Build and Test\non: [push, pull_request]\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        go: [\"1.23\", \"1.22\", \"1.21\"]\n    name: Go ${{ matrix.go }} - Build\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-go@v2\n        with:\n          go-version: ${{ matrix.go }}\n      - uses: actions/setup-node@v2\n        with:\n          node-version: \"16\"\n      - uses: actions/cache@v2\n        with:\n          path: |\n            ~/.cache/go-build\n            ~/go/pkg/mod\n          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}\n          restore-keys: |\n            ${{ runner.os }}-go-\n      - uses: actions/cache@v2\n        with:\n          path: ${{ github.workspace }}/admin/.next/cache\n          key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}\n          restore-keys: |\n            ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-\n      - run: make build\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        go: [\"1.23\", \"1.22\", \"1.21\"]\n    name: Go ${{ matrix.go }} - Test\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-go@v2\n        with:\n          go-version: ${{ matrix.go }}\n      - uses: actions/cache@v2\n        with:\n          path: |\n            ~/.cache/go-build\n            ~/go/pkg/mod\n          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}\n          restore-keys: |\n            ${{ runner.os }}-go-\n      - run: go test ./pkg/...\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: Lint\non: [push, pull_request]\ndefaults:\n  run:\n    working-directory: ./admin\njobs:\n  lint-admin:\n    runs-on: ubuntu-latest\n    name: Admin (Next.js)\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-node@v2\n        with:\n          node-version: \"16\"\n      - run: yarn install\n      - run: yarn run lint"
  },
  {
    "path": ".gitignore",
    "content": "*.vscode\n/dist\n/hetty\n/cmd/hetty/admin\n*.pem\n*.test"
  },
  {
    "path": ".golangci.yml",
    "content": "linters:\n  presets:\n    - bugs\n    - comment\n    - error\n    - format\n    - import\n    - metalinter\n    - module\n    - performance\n    - style\n    - test\n    - unused\n  disable:\n    - dupl\n    - exhaustive\n    - exhaustivestruct\n    - gochecknoglobals\n    - gochecknoinits\n    - godox\n    - goerr113\n    - gomnd\n    - interfacer\n    - maligned\n    - nilnil\n    - nlreturn\n    - scopelint \n    - testpackage\n    - varnamelen\n    - wrapcheck\n\nlinters-settings:\n  gci:\n    local-prefixes: github.com/dstotijn/hetty\n  godot:\n    capital: true\n  ireturn:\n    allow: \"error,empty,anon,stdlib,.*(or|er)$,github.com/99designs/gqlgen/graphql.Marshaler,github.com/dstotijn/hetty/pkg/api.QueryResolver,github.com/dstotijn/hetty/pkg/filter.Expression\"\n    \nissues:\n  exclude-rules:\n    - linters:\n      - gosec\n      # Ignore SHA1 usage.\n      text: \"G(401|505):\"\n    - linters:\n      - wsl\n      # Ignore cuddled defer statements.\n      text: \"only one cuddle assignment allowed before defer statement\"\n    - linters:\n      - nlreturn\n      # Ignore `break` without leading blank line.\n      text: \"break with no blank line before\""
  },
  {
    "path": ".goreleaser.yml",
    "content": "before:\n  hooks:\n    - make clean\n    - sh -c \"NEXT_PUBLIC_VERSION={{ .Version}} make build-admin\"\n    - go mod tidy\n\nbuilds:\n  - env:\n      - CGO_ENABLED=0\n    main: ./cmd/hetty\n    ldflags:\n      - -s -w -X main.version={{.Version}}\n    goos:\n      - linux\n      - windows\n      - darwin\n    goarch:\n      - amd64\n      - arm64\n\narchives:\n  - replacements:\n      darwin: macOS\n      linux: Linux\n      windows: Windows\n      amd64: x86_64\n    format_overrides:\n      - goos: windows\n        format: zip\n\nbrews:\n  - tap:\n      owner: hettysoft\n      name: homebrew-tap\n    folder: Formula\n    homepage:  https://hetty.xyz\n    description: An HTTP toolkit for security research.\n    license: MIT\n    commit_author:\n      name: David Stotijn\n      email: dstotijn@gmail.com\n    test: |\n      system \"#{bin}/hetty -v\"\n\nsnapcrafts:\n  - publish: true\n    summary: An HTTP toolkit for security research.\n    description: |\n      Hetty is an HTTP toolkit for security research. It aims to become an open\n      source alternative to commercial software like Burp Suite Pro, with\n      powerful features tailored to the needs of the infosec and bug bounty\n      community.\n    grade: stable\n    confinement: strict\n    license: MIT\n    apps:\n      hetty:\n        command: hetty\n        plugs: [\"network\", \"network-bind\"]\n\nscoop:\n  bucket:\n    owner: hettysoft\n    name: scoop-bucket\n  commit_author:\n    name: David Stotijn\n    email: dstotijn@gmail.com\n  homepage:  https://hetty.xyz\n  description: An HTTP toolkit for security research.\n  license: MIT\n\ndockers:\n  - extra_files:\n    - go.mod\n    - go.sum\n    - pkg\n    - cmd\n    - admin\n    image_templates:\n    - \"ghcr.io/dstotijn/hetty:{{ .Version }}\"\n    - \"ghcr.io/dstotijn/hetty:{{ .Major }}\"\n    - \"ghcr.io/dstotijn/hetty:{{ .Major }}.{{ .Minor }}\"\n    - \"ghcr.io/dstotijn/hetty:latest\"\n    - \"dstotijn/hetty:{{ .Version }}\"\n    - \"dstotijn/hetty:{{ .Major }}\"\n    - \"dstotijn/hetty:{{ .Major }}.{{ .Minor }}\"\n    - \"dstotijn/hetty:latest\"\n    build_flag_templates:\n    - \"--pull\"\n    - \"--label=org.opencontainers.image.created={{.Date}}\"\n    - \"--label=org.opencontainers.image.title={{.ProjectName}}\"\n    - \"--label=org.opencontainers.image.revision={{.FullCommit}}\"\n    - \"--label=org.opencontainers.image.version={{.Version}}\"\n    - \"--label=org.opencontainers.image.source=https://github.com/dstotijn/hetty\"\n    - \"--build-arg=HETTY_VERSION={{.Version}}\"\n\nchecksum:\n  name_template: \"checksums.txt\"\n\nsnapshot:\n  name_template: \"{{ incpatch .Version }}-next\"\n\nchangelog:\n  sort: asc\n  filters:\n    exclude:\n      - \"^docs:\"\n      - \"^test:\""
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at dstotijn@gmail.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contribution Guidelines\n\nThank you for taking an interest in Hetty! If you want to contribute to the\nproject, please read the guidelines below to ensure a smooth develop experience.\n\n## Code of conduct\n\nPlease first read the [code of conduct](CODE_OF_CONDUCT.md), and abide to it\nwhenever you interact with the community.\n\n## Issues\n\nUse [issues](https://github.com/dstotijn/hetty/issues) for reporting bugs,\nadding feature requests and giving context to PRs you submit. Please use [labels](https://github.com/dstotijn/hetty/labels)\nin favor of category prefixes in issue titles. To keep the issue tracker\nfocused on development, use [discussions](https://github.com/dstotijn/hetty/discussions)\nfor usage questions and non-code related discourse.\n\nBefore submitting new feature requests, check out the Kanban board for the\nstatus of on-going work. There might already be a card/issue.\n\n## Pull requests\n\nBefore submitting a pull request that introduces a new feature or significantly\nchanges the behavior of Hetty, please consider first using [discussions](https://github.com/dstotijn/hetty/discussions)\nor commenting on a relevant existing issue to share what you have in mind.\nBecause the project is in an early stage, this is especially important; there\nare still a lot of major design decisions to be made. Until the foundation has\nsolidified, design and implementation leading up to the first milestone (v1.0)\nis highly in flux, and your work might not align/be applicable for what the\nmaintainers have envisioned.\n\n## Development\n\n_Todo: Write steps for setting up local development environment._\n"
  },
  {
    "path": "Dockerfile",
    "content": "ARG GO_VERSION=1.17\nARG NODE_VERSION=16.13\nARG ALPINE_VERSION=3.15\n\nFROM node:${NODE_VERSION}-alpine AS node-builder\nWORKDIR /app\nCOPY admin/package.json admin/yarn.lock ./\nRUN yarn install --frozen-lockfile\nCOPY admin/ .\nENV NEXT_TELEMETRY_DISABLED=1\nRUN yarn run export\n\nFROM golang:${GO_VERSION}-alpine AS go-builder\nARG HETTY_VERSION=0.0.0\nENV CGO_ENABLED=0\nWORKDIR /app\nCOPY go.mod go.sum ./\nRUN go mod download\nCOPY cmd ./cmd\nCOPY pkg ./pkg\nCOPY --from=node-builder /app/dist ./cmd/hetty/admin\nRUN go build -ldflags=\"-s -w -X main.version=${HETTY_VERSION}\" ./cmd/hetty\n\nFROM alpine:${ALPINE_VERSION}\nWORKDIR /app\nCOPY --from=go-builder /app/hetty .\n\nENTRYPOINT [\"./hetty\"]\n\nEXPOSE 8080"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 David Stotijn\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "export CGO_ENABLED = 0\nexport NEXT_TELEMETRY_DISABLED = 1\n\n.PHONY: build\nbuild: build-admin\n\tgo build ./cmd/hetty\n\n.PHONY: build-admin\nbuild-admin:\n\tcd admin && \\\n\tyarn install --frozen-lockfile && \\\n\tyarn run export && \\\n    mv dist ../cmd/hetty/admin\n\n.PHONY: clean\nclean:\n\trm -f hetty\n\trm -rf ./cmd/hetty/admin\n\trm -rf ./admin/dist\n\trm -rf ./admin/.next"
  },
  {
    "path": "README.md",
    "content": "<img src=\"https://user-images.githubusercontent.com/983924/156430531-6193e187-7400-436b-81c6-f86862783ea5.svg#gh-light-mode-only\" width=\"240\"/>\n<img src=\"https://user-images.githubusercontent.com/983924/156430660-9d5bd555-dcfd-47e2-ba70-54294c20c1b4.svg#gh-dark-mode-only\" width=\"240\"/>\n\n[![Latest GitHub release](https://img.shields.io/github/v/release/dstotijn/hetty?color=25ae8f)](https://github.com/dstotijn/hetty/releases/latest)\n[![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fdstotijn%2Fhetty%2Fbadge%3Fref%3Dmain&label=build&color=24ae8f)](https://github.com/dstotijn/hetty/actions/workflows/build-test.yml)\n![GitHub download count](https://img.shields.io/github/downloads/dstotijn/hetty/total?color=25ae8f)\n[![GitHub](https://img.shields.io/github/license/dstotijn/hetty?color=25ae8f)](https://github.com/dstotijn/hetty/blob/master/LICENSE)\n[![Documentation](https://img.shields.io/badge/hetty-docs-25ae8f)](https://hetty.xyz/)\n\n**Hetty** is an HTTP toolkit for security research. It aims to become an open\nsource alternative to commercial software like Burp Suite Pro, with powerful\nfeatures tailored to the needs of the infosec and bug bounty community.\n\n<img src=\"https://hetty.xyz/img/hero.png\" width=\"907\" alt=\"Hetty proxy logs (screenshot)\" />\n\n## Features\n\n- Machine-in-the-middle (MITM) HTTP proxy, with logs and advanced search\n- HTTP client for manually creating/editing requests, and replay proxied requests\n- Intercept requests and responses for manual review (edit, send/receive, cancel)\n- Scope support, to help keep work organized\n- Easy-to-use web based admin interface\n- Project based database storage, to help keep work organized\n\n👷‍♂️ Hetty is under active development. Check the <a\nhref=\"https://github.com/dstotijn/hetty/projects/1\">backlog</a> for the current\nstatus.\n\n📣 Are you pen testing professionaly in a team? I would love to hear your\nthoughts on tooling via [this 5 minute\nsurvey](https://forms.gle/36jtgNc3TJ2imi5A8). Thank you!\n\n## Getting started\n\n💡 The [Getting started](https://hetty.xyz/docs/getting-started) doc has more\ndetailed install and usage instructions.\n\n### Installation\n\nThe quickest way to install and update Hetty is via a package manager:\n\n#### macOS\n\n```sh\nbrew install hettysoft/tap/hetty\n```\n\n#### Linux\n\n```sh\nsudo snap install hetty\n```\n\n#### Windows\n\n```sh\nscoop bucket add hettysoft https://github.com/hettysoft/scoop-bucket.git\nscoop install hettysoft/hetty\n```\n\n#### Other\n\nAlternatively, you can [download the latest release from\nGitHub](https://github.com/dstotijn/hetty/releases/latest) for your OS and\narchitecture, and move the binary to a directory in your `$PATH`. If your OS is\nnot available for one of the package managers or not listed in the GitHub\nreleases, you can compile from source _(link coming soon)_.\n\n#### Docker\n\nDocker images are distributed via [GitHub's Container registry](https://github.com/dstotijn/hetty/pkgs/container/hetty)\nand [Docker Hub](https://hub.docker.com/r/dstotijn/hetty). To run Hetty via with a volume for database and certificate\nstorage, and port 8080 forwarded:\n\n```\ndocker run -v $HOME/.hetty:/root/.hetty -p 8080:8080 \\\n  ghcr.io/dstotijn/hetty:latest\n```\n\n### Usage\n\nOnce installed, start Hetty via:\n\n```sh\nhetty\n```\n\n💡 Read the [Getting started](https://hetty.xyz/docs/getting-started) doc for\nmore details.\n\nTo list all available options, run: `hetty --help`:\n\n```\n$ hetty --help\n\nUsage:\n    hetty [flags] [subcommand] [flags]\n\nRuns an HTTP server with (MITM) proxy, GraphQL service, and a web based admin interface.\n\nOptions:\n    --cert         Path to root CA certificate. Creates file if it doesn't exist. (Default: \"~/.hetty/hetty_cert.pem\")\n    --key          Path to root CA private key. Creates file if it doesn't exist. (Default: \"~/.hetty/hetty_key.pem\")\n    --db           Database file path. Creates file if it doesn't exist. (Default: \"~/.hetty/hetty.db\")\n    --addr         TCP address for HTTP server to listen on, in the form \\\"host:port\\\". (Default: \":8080\")\n    --chrome       Launch Chrome with proxy settings applied and certificate errors ignored. (Default: false)\n    --verbose      Enable verbose logging.\n    --json         Encode logs as JSON, instead of pretty/human readable output.\n    --version, -v  Output version.\n    --help, -h     Output this usage text.\n\nSubcommands:\n    - cert  Certificate management\n\nRun `hetty <subcommand> --help` for subcommand specific usage instructions.\n\nVisit https://hetty.xyz to learn more about Hetty.\n```\n\n## Documentation\n\n📖 [Read the docs](https://hetty.xyz/docs)\n\n## Support\n\nUse [issues](https://github.com/dstotijn/hetty/issues) for bug reports and\nfeature requests, and\n[discussions](https://github.com/dstotijn/hetty/discussions) for questions and\ntroubleshooting.\n\n## Community\n\n💬 [Join the Hetty Discord server](https://discord.gg/3HVsj5pTFP)\n\n## Contributing\n\nWant to contribute? Great! Please check the [Contribution\nGuidelines](CONTRIBUTING.md) for details.\n\n## Acknowledgements\n\n- Thanks to the [Hacker101 community on Discord](https://www.hacker101.com/discord)\n  for the encouragement and early feedback.\n- The font used in the logo and admin interface is [JetBrains\n  Mono](https://www.jetbrains.com/lp/mono/).\n\n## Sponsors\n\n💖 Are you enjoying Hetty? You can [sponsor me](https://github.com/sponsors/dstotijn)!\n\n## License\n\n[MIT](LICENSE)\n\n© 2019–2025 Hetty Software\n"
  },
  {
    "path": "admin/.eslintrc.json",
    "content": "{\n  \"root\": true,\n  \"extends\": [\"next/core-web-vitals\", \"prettier\", \"plugin:@typescript-eslint/recommended\", \"plugin:import/typescript\"],\n  \"plugins\": [\"prettier\", \"@typescript-eslint\", \"import\"],\n  \"ignorePatterns\": [\"next*\", \"src/lib/graphql/generated.tsx\"],\n  \"settings\": {\n    \"import/parsers\": {\n      \"@typescript-eslint/parser\": [\".ts\", \".tsx\"]\n    },\n    \"import/resolver\": {\n      \"typescript\": {\n        \"alwaysTryTypes\": true\n      }\n    }\n  },\n  \"rules\": {\n    \"prettier/prettier\": [\"error\"],\n    \"@next/next/no-css-tags\": \"off\",\n    \"no-unused-vars\": \"off\",\n    \"@typescript-eslint/no-unused-vars\": [\n      \"error\",\n      {\n        \"ignoreRestSiblings\": true\n      }\n    ],\n\n    \"import/default\": \"off\",\n\n    \"import/no-unresolved\": \"error\",\n    \"import/named\": \"error\",\n    \"import/namespace\": \"error\",\n    \"import/export\": \"error\",\n    \"import/no-deprecated\": \"error\",\n    \"import/no-cycle\": \"error\",\n\n    \"import/no-named-as-default\": \"warn\",\n    \"import/no-named-as-default-member\": \"warn\",\n    \"import/no-duplicates\": \"warn\",\n    \"import/newline-after-import\": \"warn\",\n    \"import/order\": [\n      \"warn\",\n      {\n        \"alphabetize\": { \"order\": \"asc\", \"caseInsensitive\": false },\n        \"newlines-between\": \"always\",\n        \"groups\": [\"builtin\", \"external\", \"parent\", \"sibling\", \"index\"]\n      }\n    ],\n    \"import/no-unused-modules\": [\n      \"error\",\n      {\n        \"missingExports\": true,\n        \"ignoreExports\": [\"./src/pages\"]\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "admin/.gitignore",
    "content": "/node_modules\n/.next\n/dist\n\n*.log*\n"
  },
  {
    "path": "admin/.prettierignore",
    "content": "/.next/\n/out/\n/build\n/coverage\n"
  },
  {
    "path": "admin/.prettierrc.json",
    "content": "{\n    \"printWidth\": 120\n}\n"
  },
  {
    "path": "admin/gqlcodegen.yml",
    "content": "overwrite: true\nschema: \"../pkg/api/schema.graphql\"\ndocuments: \"src/**/*.graphql\"\ngenerates:\n  src/lib/graphql/generated.tsx:\n    plugins:\n      - \"typescript\"\n      - \"typescript-operations\"\n      - \"typescript-react-apollo\"\n"
  },
  {
    "path": "admin/next-env.d.ts",
    "content": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edited\n// see https://nextjs.org/docs/basic-features/typescript for more information.\n"
  },
  {
    "path": "admin/next.config.js",
    "content": "// @ts-check\n\n/**\n * @type {import('next').NextConfig}\n **/\nconst nextConfig = {\n  reactStrictMode: true,\n  trailingSlash: true,\n  async rewrites() {\n    return [\n      {\n        source: \"/api/:path/\",\n        destination: \"http://localhost:8080/api/:path/\",\n      },\n    ];\n  },\n};\n\nmodule.exports = nextConfig;\n"
  },
  {
    "path": "admin/package.json",
    "content": "{\n  \"name\": \"hetty-admin\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next build\",\n    \"start\": \"next start\",\n    \"lint\": \"next lint\",\n    \"export\": \"next build && next export -o dist\",\n    \"generate\": \"graphql-codegen --config gqlcodegen.yml\"\n  },\n  \"dependencies\": {\n    \"@apollo/client\": \"^3.2.0\",\n    \"@emotion/react\": \"^11.7.1\",\n    \"@emotion/server\": \"^11.4.0\",\n    \"@emotion/styled\": \"^11.6.0\",\n    \"@monaco-editor/react\": \"^4.3.1\",\n    \"@mui/icons-material\": \"^5.3.1\",\n    \"@mui/lab\": \"^5.0.0-alpha.66\",\n    \"@mui/material\": \"^5.3.1\",\n    \"@mui/styles\": \"^5.4.2\",\n    \"allotment\": \"^1.9.0\",\n    \"deepmerge\": \"^4.2.2\",\n    \"graphql\": \"^16.2.0\",\n    \"lodash\": \"^4.17.21\",\n    \"monaco-editor\": \"^0.31.1\",\n    \"next\": \"^12.0.8\",\n    \"next-fonts\": \"^1.0.3\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-split-pane\": \"^0.1.92\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.0.0\",\n    \"@graphql-codegen/cli\": \"2.6.1\",\n    \"@graphql-codegen/introspection\": \"2.1.1\",\n    \"@graphql-codegen/typescript\": \"2.4.3\",\n    \"@graphql-codegen/typescript-operations\": \"2.3.0\",\n    \"@graphql-codegen/typescript-react-apollo\": \"3.2.6\",\n    \"@types/lodash\": \"^4.14.178\",\n    \"@types/node\": \"^17.0.12\",\n    \"@types/react\": \"^17.0.38\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.12.0\",\n    \"@typescript-eslint/parser\": \"^5.12.0\",\n    \"eslint\": \"^8.7.0\",\n    \"eslint-config-next\": \"12.0.8\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-import-resolver-typescript\": \"^2.5.0\",\n    \"eslint-plugin-import\": \"^2.25.4\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"prettier\": \"^2.1.2\",\n    \"typescript\": \"^4.0.3\",\n    \"webpack\": \"^5.67.0\"\n  }\n}\n"
  },
  {
    "path": "admin/public/site.webmanifest",
    "content": "{\"name\":\"\",\"short_name\":\"\",\"icons\":[{\"src\":\"/android-chrome-192x192.png\",\"sizes\":\"192x192\",\"type\":\"image/png\"},{\"src\":\"/android-chrome-512x512.png\",\"sizes\":\"512x512\",\"type\":\"image/png\"}],\"theme_color\":\"#ffffff\",\"background_color\":\"#ffffff\",\"display\":\"standalone\"}"
  },
  {
    "path": "admin/public/style.css",
    "content": "@font-face {\n  font-family: \"JetBrains Mono\";\n  src: url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff2/JetBrainsMono-Bold-Italic.woff2\")\n      format(\"woff2\"),\n    url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff/JetBrainsMono-Bold-Italic.woff\")\n      format(\"woff\");\n  font-weight: 700;\n  font-style: italic;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: \"JetBrains Mono\";\n  src: url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff2/JetBrainsMono-Bold.woff2\")\n      format(\"woff2\"),\n    url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff/JetBrainsMono-Bold.woff\")\n      format(\"woff\");\n  font-weight: 700;\n  font-style: normal;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: \"JetBrains Mono\";\n  src: url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff2/JetBrainsMono-ExtraBold-Italic.woff2\")\n      format(\"woff2\"),\n    url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff/JetBrainsMono-ExtraBold-Italic.woff\")\n      format(\"woff\");\n  font-weight: 800;\n  font-style: italic;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: \"JetBrains Mono\";\n  src: url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff2/JetBrainsMono-ExtraBold.woff2\")\n      format(\"woff2\"),\n    url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff/JetBrainsMono-ExtraBold.woff\")\n      format(\"woff\");\n  font-weight: 800;\n  font-style: normal;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: \"JetBrains Mono\";\n  src: url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff2/JetBrainsMono-Italic.woff2\")\n      format(\"woff2\"),\n    url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff/JetBrainsMono-Italic.woff\")\n      format(\"woff\");\n  font-weight: 400;\n  font-style: italic;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: \"JetBrains Mono\";\n  src: url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff2/JetBrainsMono-Medium-Italic.woff2\")\n      format(\"woff2\"),\n    url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff/JetBrainsMono-Medium-Italic.woff\")\n      format(\"woff\");\n  font-weight: 500;\n  font-style: italic;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: \"JetBrains Mono\";\n  src: url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff2/JetBrainsMono-Medium.woff2\")\n      format(\"woff2\"),\n    url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff/JetBrainsMono-Medium.woff\")\n      format(\"woff\");\n  font-weight: 500;\n  font-style: normal;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: \"JetBrains Mono\";\n  src: url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff2/JetBrainsMono-Regular.woff2\")\n      format(\"woff2\"),\n    url(\"https://cdn.jsdelivr.net/gh/JetBrains/JetBrainsMono/web/woff/JetBrainsMono-Regular.woff\")\n      format(\"woff\");\n  font-weight: 400;\n  font-style: normal;\n  font-display: swap;\n}\n\ncode {\n  font-family: \"JetBrains Mono\", monospace;\n}\n"
  },
  {
    "path": "admin/src/features/Layout.tsx",
    "content": "import AltRouteIcon from \"@mui/icons-material/AltRoute\";\nimport ChevronLeftIcon from \"@mui/icons-material/ChevronLeft\";\nimport ChevronRightIcon from \"@mui/icons-material/ChevronRight\";\nimport FolderIcon from \"@mui/icons-material/Folder\";\nimport FormatListBulletedIcon from \"@mui/icons-material/FormatListBulleted\";\nimport HomeIcon from \"@mui/icons-material/Home\";\nimport LocationSearchingIcon from \"@mui/icons-material/LocationSearching\";\nimport MenuIcon from \"@mui/icons-material/Menu\";\nimport SendIcon from \"@mui/icons-material/Send\";\nimport {\n  Theme,\n  useTheme,\n  Toolbar,\n  IconButton,\n  Typography,\n  Divider,\n  List,\n  Tooltip,\n  styled,\n  CSSObject,\n  Box,\n  ListItemText,\n  Badge,\n} from \"@mui/material\";\nimport MuiAppBar, { AppBarProps as MuiAppBarProps } from \"@mui/material/AppBar\";\nimport MuiDrawer from \"@mui/material/Drawer\";\nimport MuiListItemButton, { ListItemButtonProps } from \"@mui/material/ListItemButton\";\nimport MuiListItemIcon, { ListItemIconProps } from \"@mui/material/ListItemIcon\";\nimport Link from \"next/link\";\nimport React, { useState } from \"react\";\n\nimport { useActiveProject } from \"lib/ActiveProjectContext\";\nimport { useInterceptedRequests } from \"lib/InterceptedRequestsContext\";\n\nexport enum Page {\n  Home,\n  GetStarted,\n  Intercept,\n  Projects,\n  ProxySetup,\n  ProxyLogs,\n  Sender,\n  Scope,\n  Settings,\n}\n\nconst drawerWidth = 240;\n\nconst openedMixin = (theme: Theme): CSSObject => ({\n  width: drawerWidth,\n  transition: theme.transitions.create(\"width\", {\n    easing: theme.transitions.easing.sharp,\n    duration: theme.transitions.duration.enteringScreen,\n  }),\n  overflowX: \"hidden\",\n});\n\nconst closedMixin = (theme: Theme): CSSObject => ({\n  transition: theme.transitions.create(\"width\", {\n    easing: theme.transitions.easing.sharp,\n    duration: theme.transitions.duration.leavingScreen,\n  }),\n  overflowX: \"hidden\",\n  width: 56,\n});\n\nconst DrawerHeader = styled(\"div\")(({ theme }) => ({\n  display: \"flex\",\n  alignItems: \"center\",\n  justifyContent: \"flex-start\",\n  padding: theme.spacing(0, 1),\n  // necessary for content to be below app bar\n  ...theme.mixins.toolbar,\n}));\n\ninterface AppBarProps extends MuiAppBarProps {\n  open?: boolean;\n}\n\nconst AppBar = styled(MuiAppBar, {\n  shouldForwardProp: (prop) => prop !== \"open\",\n})<AppBarProps>(({ theme, open }) => ({\n  backgroundColor: theme.palette.secondary.dark,\n  zIndex: theme.zIndex.drawer + 1,\n  transition: theme.transitions.create([\"width\", \"margin\"], {\n    easing: theme.transitions.easing.sharp,\n    duration: theme.transitions.duration.leavingScreen,\n  }),\n  ...(open && {\n    marginLeft: drawerWidth,\n    width: `calc(100% - ${drawerWidth}px)`,\n    transition: theme.transitions.create([\"width\", \"margin\"], {\n      easing: theme.transitions.easing.sharp,\n      duration: theme.transitions.duration.enteringScreen,\n    }),\n  }),\n}));\n\nconst Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== \"open\" })(({ theme, open }) => ({\n  width: drawerWidth,\n  flexShrink: 0,\n  whiteSpace: \"nowrap\",\n  boxSizing: \"border-box\",\n  ...(open && {\n    ...openedMixin(theme),\n    \"& .MuiDrawer-paper\": openedMixin(theme),\n  }),\n  ...(!open && {\n    ...closedMixin(theme),\n    \"& .MuiDrawer-paper\": closedMixin(theme),\n  }),\n}));\n\nconst ListItemButton = styled(MuiListItemButton)<ListItemButtonProps>(({ theme }) => ({\n  [theme.breakpoints.up(\"sm\")]: {\n    px: 1,\n  },\n  \"&.MuiListItemButton-root\": {\n    \"&.Mui-selected\": {\n      backgroundColor: theme.palette.primary.main,\n      \"& .MuiListItemIcon-root\": {\n        color: theme.palette.secondary.dark,\n      },\n      \"& .MuiListItemText-root\": {\n        color: theme.palette.secondary.dark,\n      },\n    },\n  },\n}));\n\nconst ListItemIcon = styled(MuiListItemIcon)<ListItemIconProps>(() => ({\n  minWidth: 42,\n}));\n\ninterface Props {\n  children: React.ReactNode;\n  title: string;\n  page: Page;\n}\n\nexport function Layout({ title, page, children }: Props): JSX.Element {\n  const activeProject = useActiveProject();\n  const interceptedRequests = useInterceptedRequests();\n  const theme = useTheme();\n  const [open, setOpen] = useState(false);\n\n  const handleDrawerOpen = () => {\n    setOpen(true);\n  };\n\n  const handleDrawerClose = () => {\n    setOpen(false);\n  };\n\n  const SiteTitle = styled(\"span\")({\n    ...(title !== \"\" && {\n      color: theme.palette.primary.main,\n      marginRight: 4,\n    }),\n  });\n\n  return (\n    <Box sx={{ display: \"flex\", height: \"100%\" }}>\n      <AppBar position=\"fixed\" open={open}>\n        <Toolbar>\n          <IconButton\n            color=\"inherit\"\n            aria-label=\"Open drawer\"\n            onClick={handleDrawerOpen}\n            edge=\"start\"\n            sx={{\n              mr: 5,\n              ...(open && { display: \"none\" }),\n            }}\n          >\n            <MenuIcon />\n          </IconButton>\n          <Box\n            sx={{\n              display: \"flex\",\n              justifyContent: \"space-around\",\n              width: \"100%\",\n            }}\n          >\n            <Typography variant=\"h5\" noWrap sx={{ width: \"100%\" }}>\n              <SiteTitle>Hetty://</SiteTitle>\n              {title}\n            </Typography>\n            <Box sx={{ flexShrink: 0, pt: 0.75 }}>v{process.env.NEXT_PUBLIC_VERSION || \"0.0\"}</Box>\n          </Box>\n        </Toolbar>\n      </AppBar>\n      <Drawer variant=\"permanent\" open={open}>\n        <DrawerHeader>\n          <IconButton onClick={handleDrawerClose}>\n            {theme.direction === \"rtl\" ? <ChevronRightIcon /> : <ChevronLeftIcon />}\n          </IconButton>\n        </DrawerHeader>\n        <Divider />\n        <List sx={{ p: 0 }}>\n          <Link href=\"/\" passHref>\n            <ListItemButton key=\"home\" selected={page === Page.Home}>\n              <Tooltip title=\"Home\">\n                <ListItemIcon>\n                  <HomeIcon />\n                </ListItemIcon>\n              </Tooltip>\n              <ListItemText primary=\"Home\" />\n            </ListItemButton>\n          </Link>\n          <Link href=\"/proxy/logs\" passHref>\n            <ListItemButton key=\"proxyLogs\" disabled={!activeProject} selected={page === Page.ProxyLogs}>\n              <Tooltip title=\"Proxy logs\">\n                <ListItemIcon>\n                  <FormatListBulletedIcon />\n                </ListItemIcon>\n              </Tooltip>\n              <ListItemText primary=\"Logs\" />\n            </ListItemButton>\n          </Link>\n          <Link href=\"/proxy/intercept\" passHref>\n            <ListItemButton key=\"proxyIntercept\" disabled={!activeProject} selected={page === Page.Intercept}>\n              <Tooltip title=\"Proxy intercept\">\n                <ListItemIcon>\n                  <Badge color=\"error\" badgeContent={interceptedRequests?.length || 0}>\n                    <AltRouteIcon />\n                  </Badge>\n                </ListItemIcon>\n              </Tooltip>\n              <ListItemText primary=\"Intercept\" />\n            </ListItemButton>\n          </Link>\n          <Link href=\"/sender\" passHref>\n            <ListItemButton key=\"sender\" disabled={!activeProject} selected={page === Page.Sender}>\n              <Tooltip title=\"Sender\">\n                <ListItemIcon>\n                  <SendIcon />\n                </ListItemIcon>\n              </Tooltip>\n              <ListItemText primary=\"Sender\" />\n            </ListItemButton>\n          </Link>\n          <Link href=\"/scope\" passHref>\n            <ListItemButton key=\"scope\" disabled={!activeProject} selected={page === Page.Scope}>\n              <Tooltip title=\"Scope\">\n                <ListItemIcon>\n                  <LocationSearchingIcon />\n                </ListItemIcon>\n              </Tooltip>\n              <ListItemText primary=\"Scope\" />\n            </ListItemButton>\n          </Link>\n          <Link href=\"/projects\" passHref>\n            <ListItemButton key=\"projects\" selected={page === Page.Projects}>\n              <Tooltip title=\"Projects\">\n                <ListItemIcon>\n                  <FolderIcon />\n                </ListItemIcon>\n              </Tooltip>\n              <ListItemText primary=\"Projects\" />\n            </ListItemButton>\n          </Link>\n        </List>\n      </Drawer>\n      <Box component=\"main\" sx={{ flexGrow: 1, mx: 3, mt: 11 }}>\n        {children}\n      </Box>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "admin/src/features/intercept/components/EditRequest.tsx",
    "content": "import CancelIcon from \"@mui/icons-material/Cancel\";\nimport DownloadIcon from \"@mui/icons-material/Download\";\nimport SendIcon from \"@mui/icons-material/Send\";\nimport SettingsIcon from \"@mui/icons-material/Settings\";\nimport { Alert, Box, Button, CircularProgress, IconButton, Tooltip, Typography } from \"@mui/material\";\nimport { useRouter } from \"next/router\";\nimport React, { useEffect, useState } from \"react\";\n\nimport { useInterceptedRequests } from \"lib/InterceptedRequestsContext\";\nimport { KeyValuePair } from \"lib/components/KeyValuePair\";\nimport Link from \"lib/components/Link\";\nimport RequestTabs from \"lib/components/RequestTabs\";\nimport ResponseStatus from \"lib/components/ResponseStatus\";\nimport ResponseTabs from \"lib/components/ResponseTabs\";\nimport UrlBar, { HttpMethod, HttpProto, httpProtoMap } from \"lib/components/UrlBar\";\nimport {\n  HttpProtocol,\n  HttpRequest,\n  useCancelRequestMutation,\n  useCancelResponseMutation,\n  useGetInterceptedRequestQuery,\n  useModifyRequestMutation,\n  useModifyResponseMutation,\n} from \"lib/graphql/generated\";\nimport { queryParamsFromURL } from \"lib/queryParamsFromURL\";\nimport updateKeyPairItem from \"lib/updateKeyPairItem\";\nimport updateURLQueryParams from \"lib/updateURLQueryParams\";\n\nfunction EditRequest(): JSX.Element {\n  const router = useRouter();\n  const interceptedRequests = useInterceptedRequests();\n\n  useEffect(() => {\n    // If there's no request selected and there are pending reqs, navigate to\n    // the first one in the list. This helps you quickly review/handle reqs\n    // without having to manually select the next one in the requests table.\n    if (router.isReady && !router.query.id && interceptedRequests?.length) {\n      const req = interceptedRequests[0];\n      router.replace(`/proxy/intercept?id=${req.id}`);\n    }\n  }, [router, interceptedRequests]);\n\n  const reqId = router.query.id as string | undefined;\n\n  const [method, setMethod] = useState(HttpMethod.Get);\n  const [url, setURL] = useState(\"\");\n  const [proto, setProto] = useState(HttpProto.Http20);\n  const [queryParams, setQueryParams] = useState<KeyValuePair[]>([{ key: \"\", value: \"\" }]);\n  const [reqHeaders, setReqHeaders] = useState<KeyValuePair[]>([{ key: \"\", value: \"\" }]);\n  const [resHeaders, setResHeaders] = useState<KeyValuePair[]>([{ key: \"\", value: \"\" }]);\n  const [reqBody, setReqBody] = useState(\"\");\n  const [resBody, setResBody] = useState(\"\");\n\n  const handleQueryParamChange = (key: string, value: string, idx: number) => {\n    setQueryParams((prev) => {\n      const updated = updateKeyPairItem(key, value, idx, prev);\n      setURL((prev) => updateURLQueryParams(prev, updated));\n      return updated;\n    });\n  };\n  const handleQueryParamDelete = (idx: number) => {\n    setQueryParams((prev) => {\n      const updated = prev.slice(0, idx).concat(prev.slice(idx + 1, prev.length));\n      setURL((prev) => updateURLQueryParams(prev, updated));\n      return updated;\n    });\n  };\n\n  const handleReqHeaderChange = (key: string, value: string, idx: number) => {\n    setReqHeaders((prev) => updateKeyPairItem(key, value, idx, prev));\n  };\n  const handleReqHeaderDelete = (idx: number) => {\n    setReqHeaders((prev) => prev.slice(0, idx).concat(prev.slice(idx + 1, prev.length)));\n  };\n\n  const handleResHeaderChange = (key: string, value: string, idx: number) => {\n    setResHeaders((prev) => updateKeyPairItem(key, value, idx, prev));\n  };\n  const handleResHeaderDelete = (idx: number) => {\n    setResHeaders((prev) => prev.slice(0, idx).concat(prev.slice(idx + 1, prev.length)));\n  };\n\n  const handleURLChange = (url: string) => {\n    setURL(url);\n\n    const questionMarkIndex = url.indexOf(\"?\");\n    if (questionMarkIndex === -1) {\n      setQueryParams([{ key: \"\", value: \"\" }]);\n      return;\n    }\n\n    const newQueryParams = queryParamsFromURL(url);\n    // Push empty row.\n    newQueryParams.push({ key: \"\", value: \"\" });\n    setQueryParams(newQueryParams);\n  };\n\n  const getReqResult = useGetInterceptedRequestQuery({\n    variables: { id: reqId as string },\n    skip: reqId === undefined,\n    onCompleted: ({ interceptedRequest }) => {\n      if (!interceptedRequest) {\n        return;\n      }\n\n      setURL(interceptedRequest.url);\n      setMethod(interceptedRequest.method);\n      setReqBody(interceptedRequest.body || \"\");\n\n      const newQueryParams = queryParamsFromURL(interceptedRequest.url);\n      // Push empty row.\n      newQueryParams.push({ key: \"\", value: \"\" });\n      setQueryParams(newQueryParams);\n\n      const newReqHeaders = interceptedRequest.headers || [];\n      setReqHeaders([...newReqHeaders.map(({ key, value }) => ({ key, value })), { key: \"\", value: \"\" }]);\n\n      setResBody(interceptedRequest.response?.body || \"\");\n      const newResHeaders = interceptedRequest.response?.headers || [];\n      setResHeaders([...newResHeaders.map(({ key, value }) => ({ key, value })), { key: \"\", value: \"\" }]);\n    },\n  });\n  const interceptedReq =\n    reqId && !getReqResult?.data?.interceptedRequest?.response ? getReqResult?.data?.interceptedRequest : undefined;\n  const interceptedRes = reqId ? getReqResult?.data?.interceptedRequest?.response : undefined;\n\n  const [modifyRequest, modifyReqResult] = useModifyRequestMutation();\n  const [cancelRequest, cancelReqResult] = useCancelRequestMutation();\n\n  const [modifyResponse, modifyResResult] = useModifyResponseMutation();\n  const [cancelResponse, cancelResResult] = useCancelResponseMutation();\n\n  const onActionCompleted = () => {\n    setURL(\"\");\n    setMethod(HttpMethod.Get);\n    setReqBody(\"\");\n    setQueryParams([]);\n    setReqHeaders([]);\n    router.replace(`/proxy/intercept`);\n  };\n\n  const handleFormSubmit: React.FormEventHandler = (e) => {\n    e.preventDefault();\n\n    if (interceptedReq) {\n      modifyRequest({\n        variables: {\n          request: {\n            id: interceptedReq.id,\n            url,\n            method,\n            proto: httpProtoMap.get(proto) || HttpProtocol.Http20,\n            headers: reqHeaders.filter((kv) => kv.key !== \"\"),\n            body: reqBody || undefined,\n          },\n        },\n        update(cache) {\n          cache.modify({\n            fields: {\n              interceptedRequests(existing: HttpRequest[], { readField }) {\n                return existing.filter((ref) => interceptedReq.id !== readField(\"id\", ref));\n              },\n            },\n          });\n        },\n        onCompleted: onActionCompleted,\n      });\n    }\n\n    if (interceptedRes) {\n      modifyResponse({\n        variables: {\n          response: {\n            requestID: interceptedRes.id,\n            proto: interceptedRes.proto, // TODO: Allow modifying\n            statusCode: interceptedRes.statusCode, // TODO: Allow modifying\n            statusReason: interceptedRes.statusReason, // TODO: Allow modifying\n            headers: resHeaders.filter((kv) => kv.key !== \"\"),\n            body: resBody || undefined,\n          },\n        },\n        update(cache) {\n          cache.modify({\n            fields: {\n              interceptedRequests(existing: HttpRequest[], { readField }) {\n                return existing.filter((ref) => interceptedRes.id !== readField(\"id\", ref));\n              },\n            },\n          });\n        },\n        onCompleted: onActionCompleted,\n      });\n    }\n  };\n\n  const handleReqCancelClick = () => {\n    if (!interceptedReq) {\n      return;\n    }\n\n    cancelRequest({\n      variables: {\n        id: interceptedReq.id,\n      },\n      update(cache) {\n        cache.modify({\n          fields: {\n            interceptedRequests(existing: HttpRequest[], { readField }) {\n              return existing.filter((ref) => interceptedReq.id !== readField(\"id\", ref));\n            },\n          },\n        });\n      },\n      onCompleted: onActionCompleted,\n    });\n  };\n\n  const handleResCancelClick = () => {\n    if (!interceptedRes) {\n      return;\n    }\n\n    cancelResponse({\n      variables: {\n        requestID: interceptedRes.id,\n      },\n      update(cache) {\n        cache.modify({\n          fields: {\n            interceptedRequests(existing: HttpRequest[], { readField }) {\n              return existing.filter((ref) => interceptedRes.id !== readField(\"id\", ref));\n            },\n          },\n        });\n      },\n      onCompleted: onActionCompleted,\n    });\n  };\n\n  return (\n    <Box display=\"flex\" flexDirection=\"column\" height=\"100%\" gap={2}>\n      <Box component=\"form\" autoComplete=\"off\" onSubmit={handleFormSubmit}>\n        <Box sx={{ display: \"flex\", gap: 1, flexWrap: \"wrap\" }}>\n          <UrlBar\n            method={method}\n            onMethodChange={interceptedReq ? setMethod : undefined}\n            url={url.toString()}\n            onUrlChange={interceptedReq ? handleURLChange : undefined}\n            proto={proto}\n            onProtoChange={interceptedReq ? setProto : undefined}\n            sx={{ flex: \"1 auto\" }}\n          />\n          {!interceptedRes && (\n            <>\n              <Button\n                variant=\"contained\"\n                disableElevation\n                type=\"submit\"\n                disabled={!interceptedReq || modifyReqResult.loading || cancelReqResult.loading}\n                startIcon={modifyReqResult.loading ? <CircularProgress size={22} /> : <SendIcon />}\n              >\n                Send\n              </Button>\n              <Button\n                variant=\"contained\"\n                color=\"error\"\n                disableElevation\n                onClick={handleReqCancelClick}\n                disabled={!interceptedReq || modifyReqResult.loading || cancelReqResult.loading}\n                startIcon={cancelReqResult.loading ? <CircularProgress size={22} /> : <CancelIcon />}\n              >\n                Cancel\n              </Button>\n            </>\n          )}\n          {interceptedRes && (\n            <>\n              <Button\n                variant=\"contained\"\n                disableElevation\n                type=\"submit\"\n                disabled={modifyResResult.loading || cancelResResult.loading}\n                endIcon={modifyResResult.loading ? <CircularProgress size={22} /> : <DownloadIcon />}\n              >\n                Receive\n              </Button>\n              <Button\n                variant=\"contained\"\n                color=\"error\"\n                disableElevation\n                onClick={handleResCancelClick}\n                disabled={modifyResResult.loading || cancelResResult.loading}\n                endIcon={cancelResResult.loading ? <CircularProgress size={22} /> : <CancelIcon />}\n              >\n                Cancel\n              </Button>\n            </>\n          )}\n          <Tooltip title=\"Intercept settings\">\n            <IconButton LinkComponent={Link} href=\"/settings#intercept\">\n              <SettingsIcon />\n            </IconButton>\n          </Tooltip>\n        </Box>\n        {modifyReqResult.error && (\n          <Alert severity=\"error\" sx={{ mt: 1 }}>\n            {modifyReqResult.error.message}\n          </Alert>\n        )}\n        {cancelReqResult.error && (\n          <Alert severity=\"error\" sx={{ mt: 1 }}>\n            {cancelReqResult.error.message}\n          </Alert>\n        )}\n      </Box>\n\n      <Box flex=\"1 auto\" overflow=\"scroll\">\n        {interceptedReq && (\n          <Box sx={{ height: \"100%\", pb: 2 }}>\n            <Typography variant=\"overline\" color=\"textSecondary\" sx={{ position: \"absolute\", right: 0, mt: 1.2 }}>\n              Request\n            </Typography>\n            <RequestTabs\n              queryParams={interceptedReq ? queryParams : []}\n              headers={interceptedReq ? reqHeaders : []}\n              body={reqBody}\n              onQueryParamChange={interceptedReq ? handleQueryParamChange : undefined}\n              onQueryParamDelete={interceptedReq ? handleQueryParamDelete : undefined}\n              onHeaderChange={interceptedReq ? handleReqHeaderChange : undefined}\n              onHeaderDelete={interceptedReq ? handleReqHeaderDelete : undefined}\n              onBodyChange={interceptedReq ? setReqBody : undefined}\n            />\n          </Box>\n        )}\n        {interceptedRes && (\n          <Box sx={{ height: \"100%\", pb: 2 }}>\n            <Box sx={{ position: \"absolute\", right: 0, mt: 1.4 }}>\n              <Typography variant=\"overline\" color=\"textSecondary\" sx={{ float: \"right\", ml: 3 }}>\n                Response\n              </Typography>\n              {interceptedRes && (\n                <Box sx={{ float: \"right\", mt: 0.2 }}>\n                  <ResponseStatus\n                    proto={interceptedRes.proto}\n                    statusCode={interceptedRes.statusCode}\n                    statusReason={interceptedRes.statusReason}\n                  />\n                </Box>\n              )}\n            </Box>\n            <ResponseTabs\n              headers={interceptedRes ? resHeaders : []}\n              body={resBody}\n              onHeaderChange={interceptedRes ? handleResHeaderChange : undefined}\n              onHeaderDelete={interceptedRes ? handleResHeaderDelete : undefined}\n              onBodyChange={interceptedRes ? setResBody : undefined}\n              hasResponse={interceptedRes !== undefined && interceptedRes !== null}\n            />\n          </Box>\n        )}\n      </Box>\n    </Box>\n  );\n}\n\nexport default EditRequest;\n"
  },
  {
    "path": "admin/src/features/intercept/components/Intercept.tsx",
    "content": "import { Box } from \"@mui/material\";\n\nimport EditRequest from \"./EditRequest\";\nimport Requests from \"./Requests\";\n\nimport SplitPane from \"lib/components/SplitPane\";\n\nexport default function Sender(): JSX.Element {\n  return (\n    <Box sx={{ height: \"100%\", position: \"relative\" }}>\n      <SplitPane split=\"horizontal\" size=\"70%\">\n        <Box sx={{ width: \"100%\", pt: \"0.75rem\" }}>\n          <EditRequest />\n        </Box>\n        <Box sx={{ height: \"100%\", overflow: \"scroll\" }}>\n          <Requests />\n        </Box>\n      </SplitPane>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "admin/src/features/intercept/components/Requests.tsx",
    "content": "import { Box, Paper, Typography } from \"@mui/material\";\nimport { useRouter } from \"next/router\";\n\nimport { useInterceptedRequests } from \"lib/InterceptedRequestsContext\";\nimport RequestsTable from \"lib/components/RequestsTable\";\n\nfunction Requests(): JSX.Element {\n  const interceptedRequests = useInterceptedRequests();\n\n  const router = useRouter();\n  const activeId = router.query.id as string | undefined;\n\n  const handleRowClick = (id: string) => {\n    router.push(`/proxy/intercept?id=${id}`);\n  };\n\n  return (\n    <Box>\n      {interceptedRequests && interceptedRequests.length > 0 && (\n        <RequestsTable requests={interceptedRequests} onRowClick={handleRowClick} activeRowId={activeId} />\n      )}\n      <Box sx={{ mt: 2, height: \"100%\" }}>\n        {interceptedRequests?.length === 0 && (\n          <Paper variant=\"centered\">\n            <Typography>No pending intercepted requests.</Typography>\n          </Paper>\n        )}\n      </Box>\n    </Box>\n  );\n}\n\nexport default Requests;\n"
  },
  {
    "path": "admin/src/features/intercept/graphql/cancelRequest.graphql",
    "content": "mutation CancelRequest($id: ID!) {\n  cancelRequest(id: $id) {\n    success\n  }\n}\n"
  },
  {
    "path": "admin/src/features/intercept/graphql/cancelResponse.graphql",
    "content": "mutation CancelResponse($requestID: ID!) {\n  cancelResponse(requestID: $requestID) {\n    success\n  }\n}\n"
  },
  {
    "path": "admin/src/features/intercept/graphql/interceptedRequest.graphql",
    "content": "query GetInterceptedRequest($id: ID!) {\n  interceptedRequest(id: $id) {\n    id\n    url\n    method\n    proto\n    headers {\n      key\n      value\n    }\n    body\n    response {\n      id\n      proto\n      statusCode\n      statusReason\n      headers {\n        key\n        value\n      }\n      body\n    }\n  }\n}\n"
  },
  {
    "path": "admin/src/features/intercept/graphql/modifyRequest.graphql",
    "content": "mutation ModifyRequest($request: ModifyRequestInput!) {\n  modifyRequest(request: $request) {\n    success\n  }\n}\n"
  },
  {
    "path": "admin/src/features/intercept/graphql/modifyResponse.graphql",
    "content": "mutation ModifyResponse($response: ModifyResponseInput!) {\n  modifyResponse(response: $response) {\n    success\n  }\n}\n"
  },
  {
    "path": "admin/src/features/projects/components/NewProject.tsx",
    "content": "import AddIcon from \"@mui/icons-material/Add\";\nimport { Box, Button, CircularProgress, TextField, Typography } from \"@mui/material\";\nimport React, { useState } from \"react\";\n\nimport useOpenProjectMutation from \"../hooks/useOpenProjectMutation\";\n\nimport { useCreateProjectMutation } from \"lib/graphql/generated\";\n\nfunction NewProject(): JSX.Element {\n  const [name, setName] = useState(\"\");\n\n  const [createProject, createProjResult] = useCreateProjectMutation({\n    onCompleted(data) {\n      setName(\"\");\n      if (data?.createProject) {\n        openProject({ variables: { id: data.createProject?.id } });\n      }\n    },\n  });\n  const [openProject, openProjResult] = useOpenProjectMutation();\n\n  const handleCreateAndOpenProjectForm = (e: React.SyntheticEvent) => {\n    e.preventDefault();\n    createProject({ variables: { name } });\n  };\n\n  return (\n    <div>\n      <Box mb={3}>\n        <Typography variant=\"h6\">New project</Typography>\n      </Box>\n      <form onSubmit={handleCreateAndOpenProjectForm} autoComplete=\"off\">\n        <TextField\n          sx={{\n            mr: 2,\n          }}\n          color=\"primary\"\n          size=\"small\"\n          label=\"Project name\"\n          placeholder=\"Project name…\"\n          onChange={(e) => setName(e.target.value)}\n          error={Boolean(createProjResult.error || openProjResult.error)}\n          helperText={\n            (createProjResult.error && createProjResult.error.message) ||\n            (openProjResult.error && openProjResult.error.message)\n          }\n        />\n        <Button\n          type=\"submit\"\n          variant=\"contained\"\n          color=\"primary\"\n          size=\"large\"\n          sx={{\n            pt: 0.9,\n            pb: 0.7,\n          }}\n          disabled={createProjResult.loading || openProjResult.loading}\n          startIcon={createProjResult.loading || openProjResult.loading ? <CircularProgress size={22} /> : <AddIcon />}\n        >\n          Create & open project\n        </Button>\n      </form>\n    </div>\n  );\n}\n\nexport default NewProject;\n"
  },
  {
    "path": "admin/src/features/projects/components/ProjectList.tsx",
    "content": "import CloseIcon from \"@mui/icons-material/Close\";\nimport DeleteIcon from \"@mui/icons-material/Delete\";\nimport DescriptionIcon from \"@mui/icons-material/Description\";\nimport LaunchIcon from \"@mui/icons-material/Launch\";\nimport SettingsIcon from \"@mui/icons-material/Settings\";\nimport { Alert } from \"@mui/lab\";\nimport {\n  Avatar,\n  Box,\n  Button,\n  CircularProgress,\n  Dialog,\n  DialogActions,\n  DialogContent,\n  DialogContentText,\n  DialogTitle,\n  IconButton,\n  List,\n  ListItem,\n  ListItemAvatar,\n  ListItemSecondaryAction,\n  ListItemText,\n  Paper,\n  Snackbar,\n  Tooltip,\n  Typography,\n  useTheme,\n} from \"@mui/material\";\nimport React, { useState } from \"react\";\n\nimport useOpenProjectMutation from \"../hooks/useOpenProjectMutation\";\n\nimport Link, { NextLinkComposed } from \"lib/components/Link\";\nimport {\n  ProjectsQuery,\n  useCloseProjectMutation,\n  useDeleteProjectMutation,\n  useProjectsQuery,\n} from \"lib/graphql/generated\";\n\nfunction ProjectList(): JSX.Element {\n  const theme = useTheme();\n  const projResult = useProjectsQuery({ fetchPolicy: \"network-only\" });\n  const [openProject, openProjResult] = useOpenProjectMutation();\n  const [closeProject, closeProjResult] = useCloseProjectMutation({\n    errorPolicy: \"all\",\n    onCompleted() {\n      closeProjResult.client.resetStore();\n    },\n    update(cache) {\n      cache.modify({\n        fields: {\n          activeProject() {\n            return null;\n          },\n          projects(_, { DELETE }) {\n            return DELETE;\n          },\n          httpRequestLogFilter(_, { DELETE }) {\n            return DELETE;\n          },\n        },\n      });\n    },\n  });\n  const [deleteProject, deleteProjResult] = useDeleteProjectMutation({\n    errorPolicy: \"all\",\n    update(cache) {\n      cache.modify({\n        fields: {\n          projects(_, { DELETE }) {\n            return DELETE;\n          },\n        },\n      });\n      setDeleteDiagOpen(false);\n      setDeleteNotifOpen(true);\n    },\n  });\n\n  const [deleteProj, setDeleteProj] = useState<ProjectsQuery[\"projects\"][number]>();\n  const [deleteDiagOpen, setDeleteDiagOpen] = useState(false);\n  const handleDeleteButtonClick = (project: ProjectsQuery[\"projects\"][number]) => {\n    setDeleteProj(project);\n    setDeleteDiagOpen(true);\n  };\n  const handleDeleteConfirm = () => {\n    if (deleteProj) {\n      deleteProject({ variables: { id: deleteProj.id } });\n    }\n  };\n  const handleDeleteCancel = () => {\n    setDeleteDiagOpen(false);\n  };\n\n  const [deleteNotifOpen, setDeleteNotifOpen] = useState(false);\n  const handleCloseDeleteNotif = (_: Event | React.SyntheticEvent, reason?: string) => {\n    if (reason === \"clickaway\") {\n      return;\n    }\n    setDeleteNotifOpen(false);\n  };\n\n  return (\n    <div>\n      <Dialog open={deleteDiagOpen} onClose={handleDeleteCancel}>\n        <DialogTitle>\n          Delete project “<strong>{deleteProj?.name}</strong>”?\n        </DialogTitle>\n        <DialogContent>\n          <DialogContentText>\n            Deleting a project permanently removes all its data from the database. This action is irreversible.\n          </DialogContentText>\n          {deleteProjResult.error && (\n            <Alert severity=\"error\">Error closing project: {deleteProjResult.error.message}</Alert>\n          )}\n        </DialogContent>\n        <DialogActions>\n          <Button onClick={handleDeleteCancel} autoFocus color=\"secondary\" variant=\"contained\">\n            Cancel\n          </Button>\n          <Button\n            sx={{\n              color: \"white\",\n              backgroundColor: \"error.main\",\n              \"&:hover\": {\n                backgroundColor: \"error.dark\",\n              },\n            }}\n            onClick={handleDeleteConfirm}\n            disabled={deleteProjResult.loading}\n            variant=\"contained\"\n          >\n            Delete\n          </Button>\n        </DialogActions>\n      </Dialog>\n\n      <Snackbar\n        open={deleteNotifOpen}\n        autoHideDuration={3000}\n        onClose={handleCloseDeleteNotif}\n        anchorOrigin={{ horizontal: \"center\", vertical: \"bottom\" }}\n      >\n        <Alert onClose={handleCloseDeleteNotif} severity=\"info\">\n          Project <strong>{deleteProj?.name}</strong> was deleted.\n        </Alert>\n      </Snackbar>\n\n      <Box mb={3}>\n        <Typography variant=\"h6\">Manage projects</Typography>\n      </Box>\n\n      <Box mb={4}>\n        {projResult.loading && <CircularProgress />}\n        {projResult.error && <Alert severity=\"error\">Error fetching projects: {projResult.error.message}</Alert>}\n        {openProjResult.error && <Alert severity=\"error\">Error opening project: {openProjResult.error.message}</Alert>}\n        {closeProjResult.error && (\n          <Alert severity=\"error\">Error closing project: {closeProjResult.error.message}</Alert>\n        )}\n      </Box>\n\n      {projResult.data && projResult.data.projects.length > 0 && (\n        <Paper>\n          <List>\n            {projResult.data.projects.map((project) => (\n              <ListItem key={project.id}>\n                <ListItemAvatar>\n                  <Avatar\n                    sx={{\n                      ...(project.isActive && {\n                        color: theme.palette.secondary.dark,\n                        backgroundColor: theme.palette.primary.main,\n                      }),\n                    }}\n                  >\n                    <DescriptionIcon />\n                  </Avatar>\n                </ListItemAvatar>\n                <ListItemText>\n                  {project.name} {project.isActive && <em>(Active)</em>}\n                </ListItemText>\n                <ListItemSecondaryAction>\n                  <Tooltip title=\"Project settings\">\n                    <IconButton LinkComponent={Link} href=\"/settings\" disabled={!project.isActive}>\n                      <SettingsIcon />\n                    </IconButton>\n                  </Tooltip>\n                  {project.isActive && (\n                    <Tooltip title=\"Close project\">\n                      <IconButton onClick={() => closeProject()}>\n                        <CloseIcon />\n                      </IconButton>\n                    </Tooltip>\n                  )}\n                  {!project.isActive && (\n                    <Tooltip title=\"Open project\">\n                      <span>\n                        <IconButton\n                          disabled={openProjResult.loading || projResult.loading}\n                          onClick={() =>\n                            openProject({\n                              variables: { id: project.id },\n                            })\n                          }\n                        >\n                          <LaunchIcon />\n                        </IconButton>\n                      </span>\n                    </Tooltip>\n                  )}\n                  <Tooltip title=\"Delete project\">\n                    <span>\n                      <IconButton onClick={() => handleDeleteButtonClick(project)} disabled={project.isActive}>\n                        <DeleteIcon />\n                      </IconButton>\n                    </span>\n                  </Tooltip>\n                </ListItemSecondaryAction>\n              </ListItem>\n            ))}\n          </List>\n        </Paper>\n      )}\n      {projResult.data?.projects.length === 0 && (\n        <Alert severity=\"info\">There are no projects. Create one to get started.</Alert>\n      )}\n    </div>\n  );\n}\n\nexport default ProjectList;\n"
  },
  {
    "path": "admin/src/features/projects/graphql/activeProject.graphql",
    "content": "query ActiveProject {\n  activeProject {\n    id\n    name\n    isActive\n    settings {\n      intercept {\n        requestsEnabled\n        responsesEnabled\n        requestFilter\n        responseFilter\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "admin/src/features/projects/graphql/closeProject.graphql",
    "content": "mutation CloseProject {\n  closeProject {\n    success\n  }\n}\n"
  },
  {
    "path": "admin/src/features/projects/graphql/createProject.graphql",
    "content": "mutation CreateProject($name: String!) {\n  createProject(name: $name) {\n    id\n    name\n  }\n}\n"
  },
  {
    "path": "admin/src/features/projects/graphql/deleteProject.graphql",
    "content": "mutation DeleteProject($id: ID!) {\n  deleteProject(id: $id) {\n    success\n  }\n}\n"
  },
  {
    "path": "admin/src/features/projects/graphql/openProject.graphql",
    "content": "mutation OpenProject($id: ID!) {\n  openProject(id: $id) {\n    id\n    name\n    isActive\n  }\n}\n"
  },
  {
    "path": "admin/src/features/projects/graphql/projects.graphql",
    "content": "query Projects {\n  projects {\n    id\n    name\n    isActive\n  }\n}\n"
  },
  {
    "path": "admin/src/features/projects/hooks/useOpenProjectMutation.ts",
    "content": "import { gql } from \"@apollo/client\";\n\nimport { useOpenProjectMutation as _useOpenProjectMutation } from \"lib/graphql/generated\";\n\nexport default function useOpenProjectMutation() {\n  return _useOpenProjectMutation({\n    errorPolicy: \"all\",\n    update(cache, { data }) {\n      cache.modify({\n        fields: {\n          activeProject() {\n            const activeProjRef = cache.writeFragment({\n              data: data?.openProject,\n              fragment: gql`\n                fragment ActiveProject on Project {\n                  id\n                  name\n                  isActive\n                  type\n                }\n              `,\n            });\n            return activeProjRef;\n          },\n          projects(_, { DELETE }) {\n            cache.writeFragment({\n              id: data?.openProject?.id,\n              data: data?.openProject,\n              fragment: gql`\n                fragment OpenProject on Project {\n                  id\n                  name\n                  isActive\n                  type\n                }\n              `,\n            });\n            return DELETE;\n          },\n          httpRequestLogFilter(_, { DELETE }) {\n            return DELETE;\n          },\n        },\n      });\n    },\n  });\n}\n"
  },
  {
    "path": "admin/src/features/reqlog/components/Actions.tsx",
    "content": "import AltRouteIcon from \"@mui/icons-material/AltRoute\";\nimport DeleteIcon from \"@mui/icons-material/Delete\";\nimport { Alert } from \"@mui/lab\";\nimport { Badge, Button, IconButton, Tooltip } from \"@mui/material\";\nimport Link from \"next/link\";\n\nimport { useActiveProject } from \"lib/ActiveProjectContext\";\nimport { useInterceptedRequests } from \"lib/InterceptedRequestsContext\";\nimport { ConfirmationDialog, useConfirmationDialog } from \"lib/components/ConfirmationDialog\";\nimport { HttpRequestLogsDocument, useClearHttpRequestLogMutation } from \"lib/graphql/generated\";\n\nfunction Actions(): JSX.Element {\n  const activeProject = useActiveProject();\n  const interceptedRequests = useInterceptedRequests();\n  const [clearHTTPRequestLog, clearLogsResult] = useClearHttpRequestLogMutation({\n    refetchQueries: [{ query: HttpRequestLogsDocument }],\n  });\n  const clearHTTPConfirmationDialog = useConfirmationDialog();\n\n  return (\n    <div>\n      <ConfirmationDialog\n        isOpen={clearHTTPConfirmationDialog.isOpen}\n        onClose={clearHTTPConfirmationDialog.close}\n        onConfirm={clearHTTPRequestLog}\n      >\n        All proxy logs are going to be removed. This action cannot be undone.\n      </ConfirmationDialog>\n\n      {clearLogsResult.error && <Alert severity=\"error\">Failed to clear HTTP logs: {clearLogsResult.error}</Alert>}\n\n      {(activeProject?.settings.intercept.requestsEnabled || activeProject?.settings.intercept.responsesEnabled) && (\n        <Link href=\"/proxy/intercept/?id=\" passHref>\n          <Button\n            variant=\"contained\"\n            disabled={interceptedRequests === null || interceptedRequests.length === 0}\n            color=\"primary\"\n            component=\"a\"\n            size=\"large\"\n            startIcon={\n              <Badge color=\"error\" badgeContent={interceptedRequests?.length || 0}>\n                <AltRouteIcon />\n              </Badge>\n            }\n            sx={{ mr: 1 }}\n          >\n            Review Intercepted…\n          </Button>\n        </Link>\n      )}\n\n      <Tooltip title=\"Clear all\">\n        <IconButton onClick={clearHTTPConfirmationDialog.open}>\n          <DeleteIcon />\n        </IconButton>\n      </Tooltip>\n    </div>\n  );\n}\n\nexport default Actions;\n"
  },
  {
    "path": "admin/src/features/reqlog/components/LogDetail.tsx",
    "content": "import Alert from \"@mui/lab/Alert\";\nimport { Box, CircularProgress, Paper, Typography } from \"@mui/material\";\n\nimport RequestDetail from \"./RequestDetail\";\n\nimport Response from \"lib/components/Response\";\nimport SplitPane from \"lib/components/SplitPane\";\nimport { useHttpRequestLogQuery } from \"lib/graphql/generated\";\n\ninterface Props {\n  id?: string;\n}\n\nfunction LogDetail({ id }: Props): JSX.Element {\n  const { loading, error, data } = useHttpRequestLogQuery({\n    variables: { id: id as string },\n    skip: id === undefined,\n  });\n\n  if (loading) {\n    return <CircularProgress />;\n  }\n  if (error) {\n    return <Alert severity=\"error\">Error fetching logs details: {error.message}</Alert>;\n  }\n\n  if (data && !data.httpRequestLog) {\n    return (\n      <Alert severity=\"warning\">\n        Request <strong>{id}</strong> was not found.\n      </Alert>\n    );\n  }\n\n  if (!data?.httpRequestLog) {\n    return (\n      <Paper variant=\"centered\" sx={{ mt: 2 }}>\n        <Typography>Select a log entry…</Typography>\n      </Paper>\n    );\n  }\n\n  const reqLog = data.httpRequestLog;\n\n  return (\n    <SplitPane split=\"vertical\" size={\"50%\"}>\n      <RequestDetail request={reqLog} />\n      {reqLog.response && (\n        <Box sx={{ height: \"100%\", pt: 1, pl: 2, pb: 2 }}>\n          <Response response={reqLog.response} />\n        </Box>\n      )}\n    </SplitPane>\n  );\n}\n\nexport default LogDetail;\n"
  },
  {
    "path": "admin/src/features/reqlog/components/RequestDetail.tsx",
    "content": "import { Typography, Box } from \"@mui/material\";\nimport React from \"react\";\n\nimport RequestTabs from \"lib/components/RequestTabs\";\nimport { HttpRequestLogQuery } from \"lib/graphql/generated\";\nimport { queryParamsFromURL } from \"lib/queryParamsFromURL\";\n\ninterface Props {\n  request: NonNullable<HttpRequestLogQuery[\"httpRequestLog\"]>;\n}\n\nfunction RequestDetail({ request }: Props): JSX.Element {\n  const { method, url, headers, body } = request;\n\n  const parsedUrl = new URL(url);\n\n  return (\n    <Box sx={{ height: \"100%\", display: \"flex\", flexDirection: \"column\", pr: 2, pb: 2 }}>\n      <Box sx={{ p: 2, pb: 0 }}>\n        <Typography variant=\"overline\" color=\"textSecondary\" style={{ float: \"right\" }}>\n          Request\n        </Typography>\n        <Typography\n          variant=\"h6\"\n          component=\"h2\"\n          sx={{\n            fontSize: \"1rem\",\n            fontFamily: \"'JetBrains Mono', monospace\",\n            display: \"block\",\n            overflow: \"hidden\",\n            whiteSpace: \"nowrap\",\n            textOverflow: \"ellipsis\",\n            pr: 2,\n          }}\n        >\n          {method} {decodeURIComponent(parsedUrl.pathname + parsedUrl.search)}\n        </Typography>\n      </Box>\n\n      <Box flex=\"1 auto\" overflow=\"scroll\">\n        <RequestTabs headers={headers} queryParams={queryParamsFromURL(url)} body={body} />\n      </Box>\n    </Box>\n  );\n}\n\nexport default RequestDetail;\n"
  },
  {
    "path": "admin/src/features/reqlog/components/RequestLogs.tsx",
    "content": "import ContentCopyIcon from \"@mui/icons-material/ContentCopy\";\nimport {\n  Alert,\n  Box,\n  IconButton,\n  Link,\n  MenuItem,\n  Snackbar,\n  styled,\n  TableCell,\n  TableCellProps,\n  Tooltip,\n} from \"@mui/material\";\nimport { useRouter } from \"next/router\";\nimport { useState } from \"react\";\n\nimport Actions from \"./Actions\";\nimport LogDetail from \"./LogDetail\";\nimport Search from \"./Search\";\n\nimport RequestsTable from \"lib/components/RequestsTable\";\nimport SplitPane from \"lib/components/SplitPane\";\nimport useContextMenu from \"lib/components/useContextMenu\";\nimport { useCreateSenderRequestFromHttpRequestLogMutation, useHttpRequestLogsQuery } from \"lib/graphql/generated\";\n\nconst ActionsTableCell = styled(TableCell)<TableCellProps>(() => ({\n  paddingTop: 0,\n  paddingBottom: 0,\n}));\n\nexport function RequestLogs(): JSX.Element {\n  const router = useRouter();\n  const id = router.query.id as string | undefined;\n  const { data } = useHttpRequestLogsQuery({\n    pollInterval: 1000,\n  });\n\n  const [createSenderReqFromLog] = useCreateSenderRequestFromHttpRequestLogMutation({\n    onCompleted({ createSenderRequestFromHttpRequestLog }) {\n      const { id } = createSenderRequestFromHttpRequestLog;\n      setNewSenderReqId(id);\n      setCopiedReqNotifOpen(true);\n    },\n  });\n\n  const [copyToSenderId, setCopyToSenderId] = useState(\"\");\n  const [Menu, handleContextMenu, handleContextMenuClose] = useContextMenu();\n\n  const handleCopyToSenderClick = () => {\n    createSenderReqFromLog({\n      variables: {\n        id: copyToSenderId,\n      },\n    });\n    handleContextMenuClose();\n  };\n\n  const [newSenderReqId, setNewSenderReqId] = useState(\"\");\n  const [copiedReqNotifOpen, setCopiedReqNotifOpen] = useState(false);\n  const handleCloseCopiedNotif = (_: Event | React.SyntheticEvent, reason?: string) => {\n    if (reason === \"clickaway\") {\n      return;\n    }\n    setCopiedReqNotifOpen(false);\n  };\n\n  const handleRowClick = (id: string) => {\n    router.push(`/proxy/logs?id=${id}`);\n  };\n\n  const handleRowContextClick = (e: React.MouseEvent, id: string) => {\n    setCopyToSenderId(id);\n    handleContextMenu(e);\n  };\n\n  const actionsCell = (id: string) => (\n    <ActionsTableCell>\n      <Tooltip title=\"Copy to Sender\">\n        <IconButton\n          size=\"small\"\n          onClick={() => {\n            setCopyToSenderId(id);\n            createSenderReqFromLog({\n              variables: {\n                id,\n              },\n            });\n          }}\n        >\n          <ContentCopyIcon fontSize=\"small\" />\n        </IconButton>\n      </Tooltip>\n    </ActionsTableCell>\n  );\n\n  return (\n    <Box display=\"flex\" flexDirection=\"column\" height=\"100%\">\n      <Box display=\"flex\">\n        <Box flex=\"1 auto\">\n          <Search />\n        </Box>\n        <Box pt={0.5}>\n          <Actions />\n        </Box>\n      </Box>\n      <Box sx={{ display: \"flex\", flex: \"1 auto\", position: \"relative\" }}>\n        <SplitPane split=\"horizontal\" size={\"40%\"}>\n          <Box sx={{ width: \"100%\", height: \"100%\", pb: 2 }}>\n            <Box sx={{ width: \"100%\", height: \"100%\", overflow: \"scroll\" }}>\n              <Menu>\n                <MenuItem onClick={handleCopyToSenderClick}>Copy request to Sender</MenuItem>\n              </Menu>\n              <Snackbar\n                open={copiedReqNotifOpen}\n                autoHideDuration={3000}\n                onClose={handleCloseCopiedNotif}\n                anchorOrigin={{ horizontal: \"center\", vertical: \"bottom\" }}\n              >\n                <Alert onClose={handleCloseCopiedNotif} severity=\"info\">\n                  Request was copied. <Link href={`/sender?id=${newSenderReqId}`}>Edit in Sender.</Link>\n                </Alert>\n              </Snackbar>\n              <RequestsTable\n                requests={data?.httpRequestLogs || []}\n                activeRowId={id}\n                actionsCell={actionsCell}\n                onRowClick={handleRowClick}\n                onContextMenu={handleRowContextClick}\n              />\n            </Box>\n          </Box>\n          <LogDetail id={id} />\n        </SplitPane>\n      </Box>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "admin/src/features/reqlog/components/Search.tsx",
    "content": "import FilterListIcon from \"@mui/icons-material/FilterList\";\nimport SearchIcon from \"@mui/icons-material/Search\";\nimport { Alert } from \"@mui/lab\";\nimport {\n  Box,\n  Checkbox,\n  CircularProgress,\n  ClickAwayListener,\n  FormControlLabel,\n  InputBase,\n  Paper,\n  Popper,\n  Tooltip,\n  useTheme,\n} from \"@mui/material\";\nimport IconButton from \"@mui/material/IconButton\";\nimport React, { useRef, useState } from \"react\";\n\nimport {\n  HttpRequestLogFilterDocument,\n  useHttpRequestLogFilterQuery,\n  useSetHttpRequestLogFilterMutation,\n} from \"lib/graphql/generated\";\nimport { withoutTypename } from \"lib/graphql/omitTypename\";\n\nfunction Search(): JSX.Element {\n  const theme = useTheme();\n\n  const [searchExpr, setSearchExpr] = useState(\"\");\n  const filterResult = useHttpRequestLogFilterQuery({\n    onCompleted: (data) => {\n      setSearchExpr(data.httpRequestLogFilter?.searchExpression || \"\");\n    },\n  });\n  const filter = filterResult.data?.httpRequestLogFilter;\n\n  const [setFilterMutate, setFilterResult] = useSetHttpRequestLogFilterMutation({\n    update(cache, { data }) {\n      cache.writeQuery({\n        query: HttpRequestLogFilterDocument,\n        data: {\n          httpRequestLogFilter: data?.setHttpRequestLogFilter,\n        },\n      });\n    },\n  });\n\n  const filterRef = useRef<HTMLFormElement>(null);\n  const [filterOpen, setFilterOpen] = useState(false);\n\n  const handleSubmit = (e: React.SyntheticEvent) => {\n    setFilterMutate({\n      variables: {\n        filter: {\n          ...withoutTypename(filter),\n          searchExpression: searchExpr,\n        },\n      },\n    });\n    setFilterOpen(false);\n    e.preventDefault();\n  };\n\n  const handleClickAway = (event: MouseEvent | TouchEvent) => {\n    if (filterRef?.current && filterRef.current.contains(event.target as HTMLElement)) {\n      return;\n    }\n    setFilterOpen(false);\n  };\n\n  return (\n    <Box>\n      <Error prefix=\"Error fetching filter\" error={filterResult.error} />\n      <Error prefix=\"Error setting filter\" error={setFilterResult.error} />\n      <Box style={{ display: \"flex\", flex: 1 }}>\n        <ClickAwayListener onClickAway={handleClickAway}>\n          <Paper\n            component=\"form\"\n            autoComplete=\"off\"\n            onSubmit={handleSubmit}\n            ref={filterRef}\n            sx={{\n              padding: \"2px 4px\",\n              display: \"flex\",\n              alignItems: \"center\",\n              width: 400,\n            }}\n          >\n            <Tooltip title=\"Toggle filter options\">\n              <IconButton\n                onClick={() => setFilterOpen(!filterOpen)}\n                sx={{\n                  p: 1,\n                  color: filter?.onlyInScope ? \"primary.main\" : \"inherit\",\n                }}\n              >\n                {filterResult.loading || setFilterResult.loading ? (\n                  <CircularProgress sx={{ color: theme.palette.text.primary }} size={23} />\n                ) : (\n                  <FilterListIcon />\n                )}\n              </IconButton>\n            </Tooltip>\n            <InputBase\n              sx={{\n                ml: 1,\n                flex: 1,\n              }}\n              placeholder=\"Search proxy logs…\"\n              value={searchExpr}\n              onChange={(e) => setSearchExpr(e.target.value)}\n              onFocus={() => setFilterOpen(true)}\n              autoCorrect=\"false\"\n              spellCheck=\"false\"\n            />\n            <Tooltip title=\"Search\">\n              <IconButton type=\"submit\" sx={{ padding: 1.25 }}>\n                <SearchIcon />\n              </IconButton>\n            </Tooltip>\n            <Popper\n              open={filterOpen}\n              anchorEl={filterRef.current}\n              placement=\"bottom\"\n              style={{ zIndex: theme.zIndex.appBar }}\n            >\n              <Paper\n                sx={{\n                  width: 400,\n                  marginTop: 0.5,\n                  p: 1.5,\n                }}\n              >\n                <FormControlLabel\n                  control={\n                    <Checkbox\n                      checked={filter?.onlyInScope ? true : false}\n                      disabled={filterResult.loading || setFilterResult.loading}\n                      onChange={(e) =>\n                        setFilterMutate({\n                          variables: {\n                            filter: {\n                              ...withoutTypename(filter),\n                              onlyInScope: e.target.checked,\n                            },\n                          },\n                        })\n                      }\n                    />\n                  }\n                  label=\"Only show in-scope requests\"\n                />\n              </Paper>\n            </Popper>\n          </Paper>\n        </ClickAwayListener>\n      </Box>\n    </Box>\n  );\n}\n\nfunction Error(props: { prefix: string; error?: Error }) {\n  if (!props.error) return null;\n\n  return (\n    <Box mb={4}>\n      <Alert severity=\"error\">\n        {props.prefix}: {props.error.message}\n      </Alert>\n    </Box>\n  );\n}\n\nexport default Search;\n"
  },
  {
    "path": "admin/src/features/reqlog/graphql/clearHttpRequestLog.graphql",
    "content": "mutation ClearHTTPRequestLog {\n  clearHTTPRequestLog {\n    success\n  }\n}\n"
  },
  {
    "path": "admin/src/features/reqlog/graphql/httpRequestLog.graphql",
    "content": "query HttpRequestLog($id: ID!) {\n  httpRequestLog(id: $id) {\n    id\n    method\n    url\n    proto\n    headers {\n      key\n      value\n    }\n    body\n    response {\n      id\n      proto\n      headers {\n        key\n        value\n      }\n      statusCode\n      statusReason\n      body\n    }\n  }\n}\n"
  },
  {
    "path": "admin/src/features/reqlog/graphql/httpRequestLogFilter.graphql",
    "content": "query HttpRequestLogFilter {\n  httpRequestLogFilter {\n    onlyInScope\n    searchExpression\n  }\n}\n"
  },
  {
    "path": "admin/src/features/reqlog/graphql/httpRequestLogs.graphql",
    "content": "query HttpRequestLogs {\n  httpRequestLogs {\n    id\n    method\n    url\n    timestamp\n    response {\n      statusCode\n      statusReason\n    }\n  }\n}\n"
  },
  {
    "path": "admin/src/features/reqlog/graphql/setHttpRequestLogFilter.graphql",
    "content": "mutation SetHttpRequestLogFilter($filter: HttpRequestLogFilterInput) {\n  setHttpRequestLogFilter(filter: $filter) {\n    onlyInScope\n    searchExpression\n  }\n}\n"
  },
  {
    "path": "admin/src/features/reqlog/index.ts",
    "content": "import { RequestLogs } from \"./components/RequestLogs\";\n\nexport default RequestLogs;\n"
  },
  {
    "path": "admin/src/features/scope/components/AddRule.tsx",
    "content": "import { useApolloClient } from \"@apollo/client\";\nimport AddIcon from \"@mui/icons-material/Add\";\nimport { Alert } from \"@mui/lab\";\nimport {\n  Box,\n  Button,\n  CircularProgress,\n  FormControl,\n  FormControlLabel,\n  FormLabel,\n  Radio,\n  RadioGroup,\n  TextField,\n} from \"@mui/material\";\nimport React, { useState } from \"react\";\n\nimport { ScopeDocument, ScopeQuery, ScopeRule, useSetScopeMutation } from \"lib/graphql/generated\";\n\nfunction AddRule(): JSX.Element {\n  const [ruleType, setRuleType] = useState(\"url\");\n  const [expression, setExpression] = useState(\"\");\n\n  const client = useApolloClient();\n  const [setScope, { error, loading }] = useSetScopeMutation({\n    onCompleted({ setScope }) {\n      client.writeQuery({\n        query: ScopeDocument,\n        data: { scope: setScope },\n      });\n      setExpression(\"\");\n    },\n  });\n\n  const handleTypeChange = (e: React.ChangeEvent, value: string) => {\n    setRuleType(value);\n  };\n  const handleSubmit = (e: React.SyntheticEvent) => {\n    e.preventDefault();\n    let scope: ScopeRule[] = [];\n\n    try {\n      const data = client.readQuery<ScopeQuery>({\n        query: ScopeDocument,\n      });\n      if (data) {\n        scope = data.scope;\n      }\n    } catch (e) {}\n\n    setScope({\n      variables: {\n        scope: [...scope.map(({ url }) => ({ url })), { url: expression }],\n      },\n    });\n  };\n\n  return (\n    <div>\n      {error && (\n        <Box mb={4}>\n          <Alert severity=\"error\">Error adding rule: {error.message}</Alert>\n        </Box>\n      )}\n      <form onSubmit={handleSubmit} autoComplete=\"off\">\n        <FormControl fullWidth>\n          <FormLabel color=\"primary\" component=\"legend\">\n            Rule Type\n          </FormLabel>\n          <RadioGroup row name=\"ruleType\" value={ruleType} onChange={handleTypeChange}>\n            <FormControlLabel value=\"url\" control={<Radio />} label=\"URL\" />\n          </RadioGroup>\n        </FormControl>\n        <FormControl fullWidth>\n          <TextField\n            label=\"Expression\"\n            placeholder=\"^https:\\/\\/(.*)example.com(.*)\"\n            helperText=\"Regular expression to match on.\"\n            color=\"primary\"\n            variant=\"outlined\"\n            required\n            value={expression}\n            onChange={(e) => setExpression(e.target.value)}\n            InputProps={{\n              sx: { fontFamily: \"'JetBrains Mono', monospace\" },\n            }}\n            InputLabelProps={{\n              shrink: true,\n            }}\n            margin=\"normal\"\n          />\n        </FormControl>\n        <Box my={2}>\n          <Button\n            type=\"submit\"\n            variant=\"contained\"\n            color=\"primary\"\n            disabled={loading}\n            startIcon={loading ? <CircularProgress size={22} /> : <AddIcon />}\n          >\n            Add rule\n          </Button>\n        </Box>\n      </form>\n    </div>\n  );\n}\n\nexport default AddRule;\n"
  },
  {
    "path": "admin/src/features/scope/components/RuleListItem.tsx",
    "content": "import { useApolloClient } from \"@apollo/client\";\nimport CodeIcon from \"@mui/icons-material/Code\";\nimport DeleteIcon from \"@mui/icons-material/Delete\";\nimport {\n  Avatar,\n  Chip,\n  IconButton,\n  ListItem,\n  ListItemAvatar,\n  ListItemSecondaryAction,\n  ListItemText,\n  Tooltip,\n} from \"@mui/material\";\nimport React from \"react\";\n\nimport { ScopeDocument, ScopeQuery, useSetScopeMutation } from \"lib/graphql/generated\";\n\ntype ScopeRule = ScopeQuery[\"scope\"][number];\n\ntype RuleListItemProps = {\n  scope: ScopeQuery[\"scope\"];\n  rule: ScopeRule;\n  index: number;\n};\n\nfunction RuleListItem({ scope, rule, index }: RuleListItemProps): JSX.Element {\n  const client = useApolloClient();\n  const [setScope, { loading }] = useSetScopeMutation({\n    onCompleted({ setScope }) {\n      client.writeQuery({\n        query: ScopeDocument,\n        data: { scope: setScope },\n      });\n    },\n  });\n\n  const handleDelete = (index: number) => {\n    const clone = [...scope];\n    clone.splice(index, 1);\n    setScope({\n      variables: {\n        scope: clone.map(({ url }) => ({ url })),\n      },\n    });\n  };\n\n  return (\n    <ListItem>\n      <ListItemAvatar>\n        <Avatar>\n          <CodeIcon />\n        </Avatar>\n      </ListItemAvatar>\n      <RuleListItemText rule={rule} />\n      <ListItemSecondaryAction>\n        <RuleTypeChip rule={rule} />\n        <Tooltip title=\"Delete rule\">\n          <span style={{ marginLeft: 8 }}>\n            <IconButton onClick={() => handleDelete(index)} disabled={loading}>\n              <DeleteIcon />\n            </IconButton>\n          </span>\n        </Tooltip>\n      </ListItemSecondaryAction>\n    </ListItem>\n  );\n}\n\nfunction RuleListItemText({ rule }: { rule: ScopeRule }): JSX.Element {\n  let text: JSX.Element = <div></div>;\n\n  if (rule.url) {\n    text = <code>{rule.url}</code>;\n  }\n\n  // TODO: Parse and handle rule.header and rule.body.\n\n  return <ListItemText>{text}</ListItemText>;\n}\n\nfunction RuleTypeChip({ rule }: { rule: ScopeRule }): JSX.Element {\n  let label = \"Unknown\";\n\n  if (rule.url) {\n    label = \"URL\";\n  }\n\n  return <Chip label={label} variant=\"outlined\" />;\n}\n\nexport default RuleListItem;\n"
  },
  {
    "path": "admin/src/features/scope/components/Rules.tsx",
    "content": "import { Alert } from \"@mui/lab\";\nimport { CircularProgress, List } from \"@mui/material\";\nimport React from \"react\";\n\nimport RuleListItem from \"./RuleListItem\";\n\nimport { useScopeQuery } from \"lib/graphql/generated\";\n\nfunction Rules(): JSX.Element {\n  const { loading, error, data } = useScopeQuery();\n\n  return (\n    <div>\n      {loading && <CircularProgress />}\n      {error && <Alert severity=\"error\">Error fetching scope: {error.message}</Alert>}\n      {data && data.scope.length > 0 && (\n        <List\n          sx={{\n            bgcolor: \"background.paper\",\n          }}\n        >\n          {data.scope.map((rule, index) => (\n            <RuleListItem key={index} rule={rule} scope={data.scope} index={index} />\n          ))}\n        </List>\n      )}\n    </div>\n  );\n}\n\nexport default Rules;\n"
  },
  {
    "path": "admin/src/features/scope/graphql/scope.graphql",
    "content": "query Scope {\n  scope {\n    url\n  }\n}\n"
  },
  {
    "path": "admin/src/features/scope/graphql/setScope.graphql",
    "content": "mutation SetScope($scope: [ScopeRuleInput!]!) {\n  setScope(scope: $scope) {\n    url\n  }\n}\n"
  },
  {
    "path": "admin/src/features/sender/components/EditRequest.tsx",
    "content": "import AddIcon from \"@mui/icons-material/Add\";\nimport { Alert, Box, Button, Fab, Tooltip, Typography, useTheme } from \"@mui/material\";\nimport { useRouter } from \"next/router\";\nimport React, { useState } from \"react\";\n\nimport { KeyValuePair } from \"lib/components/KeyValuePair\";\nimport RequestTabs from \"lib/components/RequestTabs\";\nimport Response from \"lib/components/Response\";\nimport SplitPane from \"lib/components/SplitPane\";\nimport UrlBar, { HttpMethod, HttpProto, httpProtoMap } from \"lib/components/UrlBar\";\nimport {\n  GetSenderRequestQuery,\n  useCreateOrUpdateSenderRequestMutation,\n  useGetSenderRequestQuery,\n  useSendRequestMutation,\n} from \"lib/graphql/generated\";\nimport { queryParamsFromURL } from \"lib/queryParamsFromURL\";\nimport updateKeyPairItem from \"lib/updateKeyPairItem\";\nimport updateURLQueryParams from \"lib/updateURLQueryParams\";\n\nconst defaultMethod = HttpMethod.Get;\nconst defaultProto = HttpProto.Http20;\nconst emptyKeyPair = [{ key: \"\", value: \"\" }];\n\nfunction EditRequest(): JSX.Element {\n  const router = useRouter();\n  const reqId = router.query.id as string | undefined;\n\n  const theme = useTheme();\n\n  const [method, setMethod] = useState(defaultMethod);\n  const [url, setURL] = useState(\"\");\n  const [proto, setProto] = useState(defaultProto);\n  const [queryParams, setQueryParams] = useState<KeyValuePair[]>(emptyKeyPair);\n  const [headers, setHeaders] = useState<KeyValuePair[]>(emptyKeyPair);\n  const [body, setBody] = useState(\"\");\n\n  const handleQueryParamChange = (key: string, value: string, idx: number) => {\n    setQueryParams((prev) => {\n      const updated = updateKeyPairItem(key, value, idx, prev);\n      setURL((prev) => updateURLQueryParams(prev, updated));\n      return updated;\n    });\n  };\n  const handleQueryParamDelete = (idx: number) => {\n    setQueryParams((prev) => {\n      const updated = prev.slice(0, idx).concat(prev.slice(idx + 1, prev.length));\n      setURL((prev) => updateURLQueryParams(prev, updated));\n      return updated;\n    });\n  };\n\n  const handleHeaderChange = (key: string, value: string, idx: number) => {\n    setHeaders((prev) => updateKeyPairItem(key, value, idx, prev));\n  };\n  const handleHeaderDelete = (idx: number) => {\n    setHeaders((prev) => prev.slice(0, idx).concat(prev.slice(idx + 1, prev.length)));\n  };\n\n  const handleURLChange = (url: string) => {\n    setURL(url);\n\n    const questionMarkIndex = url.indexOf(\"?\");\n    if (questionMarkIndex === -1) {\n      setQueryParams([{ key: \"\", value: \"\" }]);\n      return;\n    }\n\n    const newQueryParams = queryParamsFromURL(url);\n    // Push empty row.\n    newQueryParams.push({ key: \"\", value: \"\" });\n    setQueryParams(newQueryParams);\n  };\n\n  const [response, setResponse] = useState<NonNullable<GetSenderRequestQuery[\"senderRequest\"]>[\"response\"]>(null);\n  const getReqResult = useGetSenderRequestQuery({\n    variables: { id: reqId as string },\n    skip: reqId === undefined,\n    onCompleted: ({ senderRequest }) => {\n      if (!senderRequest) {\n        return;\n      }\n\n      setURL(senderRequest.url);\n      setMethod(senderRequest.method);\n      setBody(senderRequest.body || \"\");\n\n      const newQueryParams = queryParamsFromURL(senderRequest.url);\n      // Push empty row.\n      newQueryParams.push({ key: \"\", value: \"\" });\n      setQueryParams(newQueryParams);\n\n      const newHeaders = senderRequest.headers || [];\n      setHeaders([...newHeaders.map(({ key, value }) => ({ key, value })), { key: \"\", value: \"\" }]);\n      setResponse(senderRequest.response);\n    },\n  });\n\n  const [createOrUpdateRequest, createResult] = useCreateOrUpdateSenderRequestMutation();\n  const [sendRequest, sendResult] = useSendRequestMutation();\n\n  const createOrUpdateRequestAndSend = () => {\n    const senderReq = getReqResult?.data?.senderRequest;\n    createOrUpdateRequest({\n      variables: {\n        request: {\n          // Update existing sender request if it was cloned from a request log\n          // and it doesn't have a response body yet (e.g. not sent yet).\n          ...(senderReq && senderReq.sourceRequestLogID && !senderReq.response && { id: senderReq.id }),\n          url,\n          method,\n          proto: httpProtoMap.get(proto),\n          headers: headers.filter((kv) => kv.key !== \"\"),\n          body: body || undefined,\n        },\n      },\n      onCompleted: ({ createOrUpdateSenderRequest }) => {\n        const { id } = createOrUpdateSenderRequest;\n        sendRequestAndPushRoute(id);\n      },\n    });\n  };\n\n  const sendRequestAndPushRoute = (id: string) => {\n    sendRequest({\n      errorPolicy: \"all\",\n      onCompleted: () => {\n        router.push(`/sender?id=${id}`);\n      },\n      variables: {\n        id,\n      },\n    });\n  };\n\n  const handleFormSubmit: React.FormEventHandler = (e) => {\n    e.preventDefault();\n    createOrUpdateRequestAndSend();\n  };\n\n  const handleNewRequest = () => {\n    setURL(\"\");\n    setMethod(defaultMethod);\n    setProto(defaultProto);\n    setQueryParams(emptyKeyPair);\n    setHeaders(emptyKeyPair);\n    setBody(\"\");\n    setResponse(null);\n    router.push(`/sender`);\n  };\n\n  return (\n    <Box display=\"flex\" flexDirection=\"column\" height=\"100%\" gap={2}>\n      <Box sx={{ position: \"absolute\", bottom: theme.spacing(2), right: theme.spacing(2) }}>\n        <Tooltip title=\"New request\">\n          <Fab color=\"primary\" onClick={handleNewRequest}>\n            <AddIcon />\n          </Fab>\n        </Tooltip>\n      </Box>\n      <Box component=\"form\" autoComplete=\"off\" onSubmit={handleFormSubmit}>\n        <Box sx={{ display: \"flex\", gap: 1, flexWrap: \"wrap\" }}>\n          <UrlBar\n            method={method}\n            onMethodChange={setMethod}\n            url={url.toString()}\n            onUrlChange={handleURLChange}\n            proto={proto}\n            onProtoChange={setProto}\n            sx={{ flex: \"1 auto\" }}\n          />\n          <Button\n            variant=\"contained\"\n            disableElevation\n            sx={{ width: \"8rem\" }}\n            type=\"submit\"\n            disabled={createResult.loading || sendResult.loading}\n          >\n            Send\n          </Button>\n        </Box>\n        {createResult.error && (\n          <Alert severity=\"error\" sx={{ mt: 1 }}>\n            {createResult.error.message}\n          </Alert>\n        )}\n        {sendResult.error && (\n          <Alert severity=\"error\" sx={{ mt: 1 }}>\n            {sendResult.error.message}\n          </Alert>\n        )}\n      </Box>\n\n      <Box flex=\"1 auto\" position=\"relative\">\n        <SplitPane split=\"vertical\" size={\"50%\"}>\n          <Box sx={{ height: \"100%\", mr: 2, pb: 2, position: \"relative\" }}>\n            <Typography variant=\"overline\" color=\"textSecondary\" sx={{ position: \"absolute\", right: 0, mt: 1.2 }}>\n              Request\n            </Typography>\n            <RequestTabs\n              queryParams={queryParams}\n              headers={headers}\n              body={body}\n              onQueryParamChange={handleQueryParamChange}\n              onQueryParamDelete={handleQueryParamDelete}\n              onHeaderChange={handleHeaderChange}\n              onHeaderDelete={handleHeaderDelete}\n              onBodyChange={setBody}\n            />\n          </Box>\n          <Box sx={{ height: \"100%\", position: \"relative\", ml: 2, pb: 2 }}>\n            <Response response={response} />\n          </Box>\n        </SplitPane>\n      </Box>\n    </Box>\n  );\n}\n\nexport default EditRequest;\n"
  },
  {
    "path": "admin/src/features/sender/components/History.tsx",
    "content": "import { Box, Paper, Typography } from \"@mui/material\";\nimport { useRouter } from \"next/router\";\n\nimport RequestsTable from \"lib/components/RequestsTable\";\nimport { useGetSenderRequestsQuery } from \"lib/graphql/generated\";\n\nfunction History(): JSX.Element {\n  const { data, loading } = useGetSenderRequestsQuery({\n    pollInterval: 1000,\n  });\n\n  const router = useRouter();\n  const activeId = router.query.id as string | undefined;\n\n  const handleRowClick = (id: string) => {\n    router.push(`/sender?id=${id}`);\n  };\n\n  return (\n    <Box>\n      {!loading && data?.senderRequests && data?.senderRequests.length > 0 && (\n        <RequestsTable requests={data.senderRequests} onRowClick={handleRowClick} activeRowId={activeId} />\n      )}\n      <Box sx={{ mt: 2, height: \"100%\" }}>\n        {!loading && data?.senderRequests.length === 0 && (\n          <Paper variant=\"centered\">\n            <Typography>No requests created yet.</Typography>\n          </Paper>\n        )}\n      </Box>\n    </Box>\n  );\n}\n\nexport default History;\n"
  },
  {
    "path": "admin/src/features/sender/components/Sender.tsx",
    "content": "import { Box } from \"@mui/material\";\n\nimport EditRequest from \"./EditRequest\";\nimport History from \"./History\";\n\nimport SplitPane from \"lib/components/SplitPane\";\n\nexport default function Sender(): JSX.Element {\n  return (\n    <Box sx={{ height: \"100%\", position: \"relative\" }}>\n      <SplitPane split=\"horizontal\" size=\"70%\">\n        <Box sx={{ width: \"100%\", pt: \"0.75rem\" }}>\n          <EditRequest />\n        </Box>\n        <Box sx={{ height: \"100%\", overflow: \"scroll\" }}>\n          <History />\n        </Box>\n      </SplitPane>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "admin/src/features/sender/graphql/createOrUpdateRequest.graphql",
    "content": "mutation CreateOrUpdateSenderRequest($request: SenderRequestInput!) {\n  createOrUpdateSenderRequest(request: $request) {\n    id\n  }\n}\n"
  },
  {
    "path": "admin/src/features/sender/graphql/createSenderRequestFromRequestLog.graphql",
    "content": "mutation CreateSenderRequestFromHttpRequestLog($id: ID!) {\n  createSenderRequestFromHttpRequestLog(id: $id) {\n    id\n  }\n}\n"
  },
  {
    "path": "admin/src/features/sender/graphql/sendRequest.graphql",
    "content": "mutation SendRequest($id: ID!) {\n  sendRequest(id: $id) {\n    id\n  }\n}\n"
  },
  {
    "path": "admin/src/features/sender/graphql/senderRequest.graphql",
    "content": "query GetSenderRequest($id: ID!) {\n  senderRequest(id: $id) {\n    id\n    sourceRequestLogID\n    url\n    method\n    proto\n    headers {\n      key\n      value\n    }\n    body\n    timestamp\n    response {\n      id\n      proto\n      statusCode\n      statusReason\n      body\n      headers {\n        key\n        value\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "admin/src/features/sender/graphql/senderRequests.graphql",
    "content": "query GetSenderRequests {\n  senderRequests {\n    id\n    url\n    method\n    response {\n      id\n      statusCode\n      statusReason\n    }\n  }\n}\n"
  },
  {
    "path": "admin/src/features/sender/index.ts",
    "content": "import Sender from \"./components/Sender\";\n\nexport default Sender;\n"
  },
  {
    "path": "admin/src/features/settings/components/Settings.tsx",
    "content": "import { useApolloClient } from \"@apollo/client\";\nimport { TabContext, TabPanel } from \"@mui/lab\";\nimport TabList from \"@mui/lab/TabList\";\nimport {\n  Alert,\n  Box,\n  Button,\n  CircularProgress,\n  FormControl,\n  FormControlLabel,\n  FormHelperText,\n  Snackbar,\n  Switch,\n  Tab,\n  TextField,\n  TextFieldProps,\n  Typography,\n} from \"@mui/material\";\nimport MaterialLink from \"@mui/material/Link\";\nimport { SwitchBaseProps } from \"@mui/material/internal/SwitchBase\";\nimport { useEffect, useState } from \"react\";\n\nimport { useActiveProject } from \"lib/ActiveProjectContext\";\nimport Link from \"lib/components/Link\";\nimport { ActiveProjectDocument, useUpdateInterceptSettingsMutation } from \"lib/graphql/generated\";\nimport { withoutTypename } from \"lib/graphql/omitTypename\";\n\nenum TabValue {\n  Intercept = \"intercept\",\n}\n\nfunction FilterTextField(props: TextFieldProps): JSX.Element {\n  return (\n    <TextField\n      color=\"primary\"\n      variant=\"outlined\"\n      InputProps={{\n        sx: { fontFamily: \"'JetBrains Mono', monospace\" },\n        autoCorrect: \"false\",\n        spellCheck: \"false\",\n      }}\n      InputLabelProps={{\n        shrink: true,\n      }}\n      margin=\"normal\"\n      sx={{ mr: 1 }}\n      {...props}\n    />\n  );\n}\n\nexport default function Settings(): JSX.Element {\n  const client = useApolloClient();\n  const activeProject = useActiveProject();\n  const [updateInterceptSettings, updateIntercepSettingsResult] = useUpdateInterceptSettingsMutation({\n    onCompleted(data) {\n      client.cache.updateQuery({ query: ActiveProjectDocument }, (cachedData) => ({\n        activeProject: {\n          ...cachedData.activeProject,\n          settings: {\n            ...cachedData.activeProject.settings,\n            intercept: data.updateInterceptSettings,\n          },\n        },\n      }));\n\n      setInterceptReqFilter(data.updateInterceptSettings.requestFilter || \"\");\n      setInterceptResFilter(data.updateInterceptSettings.responseFilter || \"\");\n      setSettingsUpdatedOpen(true);\n    },\n  });\n\n  const [interceptReqFilter, setInterceptReqFilter] = useState(\"\");\n  const [interceptResFilter, setInterceptResFilter] = useState(\"\");\n\n  useEffect(() => {\n    setInterceptReqFilter(activeProject?.settings.intercept.requestFilter || \"\");\n  }, [activeProject?.settings.intercept.requestFilter]);\n\n  useEffect(() => {\n    setInterceptResFilter(activeProject?.settings.intercept.responseFilter || \"\");\n  }, [activeProject?.settings.intercept.responseFilter]);\n\n  const handleReqInterceptEnabled: SwitchBaseProps[\"onChange\"] = (e, checked) => {\n    if (!activeProject) {\n      e.preventDefault();\n      return;\n    }\n\n    updateInterceptSettings({\n      variables: {\n        input: {\n          ...withoutTypename(activeProject.settings.intercept),\n          requestsEnabled: checked,\n        },\n      },\n    });\n  };\n\n  const handleResInterceptEnabled: SwitchBaseProps[\"onChange\"] = (e, checked) => {\n    if (!activeProject) {\n      e.preventDefault();\n      return;\n    }\n\n    updateInterceptSettings({\n      variables: {\n        input: {\n          ...withoutTypename(activeProject.settings.intercept),\n          responsesEnabled: checked,\n        },\n      },\n    });\n  };\n\n  const handleInterceptReqFilter = () => {\n    if (!activeProject) {\n      return;\n    }\n\n    updateInterceptSettings({\n      variables: {\n        input: {\n          ...withoutTypename(activeProject.settings.intercept),\n          requestFilter: interceptReqFilter,\n        },\n      },\n    });\n  };\n\n  const handleInterceptResFilter = () => {\n    if (!activeProject) {\n      return;\n    }\n\n    updateInterceptSettings({\n      variables: {\n        input: {\n          ...withoutTypename(activeProject.settings.intercept),\n          responseFilter: interceptResFilter,\n        },\n      },\n    });\n  };\n\n  const [tabValue, setTabValue] = useState(TabValue.Intercept);\n  const [settingsUpdatedOpen, setSettingsUpdatedOpen] = useState(false);\n\n  const handleSettingsUpdatedClose = (_: Event | React.SyntheticEvent, reason?: string) => {\n    if (reason === \"clickaway\") {\n      return;\n    }\n\n    setSettingsUpdatedOpen(false);\n  };\n\n  const tabSx = {\n    textTransform: \"none\",\n  };\n\n  return (\n    <Box p={4}>\n      <Snackbar open={settingsUpdatedOpen} autoHideDuration={3000} onClose={handleSettingsUpdatedClose}>\n        <Alert onClose={handleSettingsUpdatedClose} severity=\"info\">\n          Intercept settings have been updated.\n        </Alert>\n      </Snackbar>\n\n      <Typography variant=\"h4\" sx={{ mb: 2 }}>\n        Settings\n      </Typography>\n      <Typography paragraph sx={{ mb: 4 }}>\n        Settings allow you to tweak the behaviour of Hetty’s features.\n      </Typography>\n      <Typography variant=\"h5\" sx={{ mb: 2 }}>\n        Project settings\n      </Typography>\n      {!activeProject && (\n        <Typography paragraph>\n          There is no project active. To configure project settings, first <Link href=\"/projects\">open a project</Link>.\n        </Typography>\n      )}\n      {activeProject && (\n        <>\n          <TabContext value={tabValue}>\n            <TabList onChange={(_, value) => setTabValue(value)} sx={{ borderBottom: 1, borderColor: \"divider\" }}>\n              <Tab value={TabValue.Intercept} label=\"Intercept\" sx={tabSx} />\n            </TabList>\n\n            <TabPanel value={TabValue.Intercept} sx={{ px: 0 }}>\n              <Typography variant=\"h6\" sx={{ mt: 3, mb: 1 }}>\n                Requests\n              </Typography>\n              <FormControl sx={{ mb: 2 }}>\n                <FormControlLabel\n                  control={\n                    <Switch\n                      disabled={updateIntercepSettingsResult.loading}\n                      onChange={handleReqInterceptEnabled}\n                      checked={activeProject.settings.intercept.requestsEnabled}\n                    />\n                  }\n                  label=\"Enable request interception\"\n                  labelPlacement=\"start\"\n                  sx={{ display: \"inline-block\", m: 0 }}\n                />\n                <FormHelperText>\n                  When enabled, incoming HTTP requests to the proxy are stalled for{\" \"}\n                  <Link href=\"/proxy/intercept\">manual review</Link>.\n                </FormHelperText>\n              </FormControl>\n              <form>\n                <FormControl sx={{ width: \"50%\" }}>\n                  <FilterTextField\n                    label=\"Request filter\"\n                    placeholder={`Example: method = \"GET\" OR url =~ \"/foobar\"`}\n                    value={interceptReqFilter}\n                    onChange={(e) => setInterceptReqFilter(e.target.value)}\n                  />\n                  <FormHelperText>\n                    Filter expression to match incoming requests on. When set, only matching requests are intercepted.{\" \"}\n                    <MaterialLink\n                      href=\"https://hetty.xyz/docs/guides/intercept?utm_source=hettyapp#request-filter\"\n                      target=\"_blank\"\n                    >\n                      Read docs.\n                    </MaterialLink>\n                  </FormHelperText>\n                </FormControl>\n                <Button\n                  type=\"submit\"\n                  variant=\"text\"\n                  color=\"primary\"\n                  size=\"large\"\n                  sx={{\n                    mt: 2,\n                    py: 1.8,\n                  }}\n                  onClick={handleInterceptReqFilter}\n                  disabled={updateIntercepSettingsResult.loading}\n                  startIcon={updateIntercepSettingsResult.loading ? <CircularProgress size={22} /> : undefined}\n                >\n                  Update\n                </Button>\n              </form>\n              <Typography variant=\"h6\" sx={{ mt: 3 }}>\n                Responses\n              </Typography>\n              <FormControl sx={{ mb: 2 }}>\n                <FormControlLabel\n                  control={\n                    <Switch\n                      disabled={updateIntercepSettingsResult.loading}\n                      onChange={handleResInterceptEnabled}\n                      checked={activeProject.settings.intercept.responsesEnabled}\n                    />\n                  }\n                  label=\"Enable response interception\"\n                  labelPlacement=\"start\"\n                  sx={{ display: \"inline-block\", m: 0 }}\n                />\n                <FormHelperText>\n                  When enabled, HTTP responses received by the proxy are stalled for{\" \"}\n                  <Link href=\"/proxy/intercept\">manual review</Link>.\n                </FormHelperText>\n              </FormControl>\n              <form>\n                <FormControl sx={{ width: \"50%\" }}>\n                  <FilterTextField\n                    label=\"Response filter\"\n                    placeholder={`Example: statusCode =~ \"^2\" OR body =~ \"foobar\"`}\n                    value={interceptResFilter}\n                    onChange={(e) => setInterceptResFilter(e.target.value)}\n                  />\n                  <FormHelperText>\n                    Filter expression to match received responses on. When set, only matching responses are intercepted.{\" \"}\n                    <MaterialLink\n                      href=\"https://hetty.xyz/docs/guides/intercept/?utm_source=hettyapp#response-filter\"\n                      target=\"_blank\"\n                    >\n                      Read docs.\n                    </MaterialLink>\n                  </FormHelperText>\n                </FormControl>\n                <Button\n                  type=\"submit\"\n                  variant=\"text\"\n                  color=\"primary\"\n                  size=\"large\"\n                  sx={{\n                    mt: 2,\n                    py: 1.8,\n                  }}\n                  onClick={handleInterceptResFilter}\n                  disabled={updateIntercepSettingsResult.loading}\n                  startIcon={updateIntercepSettingsResult.loading ? <CircularProgress size={22} /> : undefined}\n                >\n                  Update\n                </Button>\n              </form>\n            </TabPanel>\n          </TabContext>\n        </>\n      )}\n    </Box>\n  );\n}\n"
  },
  {
    "path": "admin/src/features/settings/graphql/updateInterceptSettings.graphql",
    "content": "mutation UpdateInterceptSettings($input: UpdateInterceptSettingsInput!) {\n  updateInterceptSettings(input: $input) {\n    requestsEnabled\n    responsesEnabled\n    requestFilter\n    responseFilter\n  }\n}\n"
  },
  {
    "path": "admin/src/lib/ActiveProjectContext.tsx",
    "content": "import React, { createContext, useContext } from \"react\";\n\nimport { Project, useActiveProjectQuery } from \"./graphql/generated\";\n\nconst ActiveProjectContext = createContext<Project | null>(null);\n\ninterface Props {\n  children?: React.ReactNode | undefined;\n}\n\nexport function ActiveProjectProvider({ children }: Props): JSX.Element {\n  const { data } = useActiveProjectQuery();\n  const project = data?.activeProject || null;\n\n  return <ActiveProjectContext.Provider value={project}>{children}</ActiveProjectContext.Provider>;\n}\n\nexport function useActiveProject() {\n  return useContext(ActiveProjectContext);\n}\n"
  },
  {
    "path": "admin/src/lib/InterceptedRequestsContext.tsx",
    "content": "import React, { createContext, useContext } from \"react\";\n\nimport { GetInterceptedRequestsQuery, useGetInterceptedRequestsQuery } from \"./graphql/generated\";\n\nconst InterceptedRequestsContext = createContext<GetInterceptedRequestsQuery[\"interceptedRequests\"] | null>(null);\n\ninterface Props {\n  children?: React.ReactNode | undefined;\n}\n\nexport function InterceptedRequestsProvider({ children }: Props): JSX.Element {\n  const { data } = useGetInterceptedRequestsQuery({\n    pollInterval: 1000,\n  });\n  const reqs = data?.interceptedRequests || null;\n\n  return <InterceptedRequestsContext.Provider value={reqs}>{children}</InterceptedRequestsContext.Provider>;\n}\n\nexport function useInterceptedRequests() {\n  return useContext(InterceptedRequestsContext);\n}\n"
  },
  {
    "path": "admin/src/lib/components/ConfirmationDialog.tsx",
    "content": "import Button from \"@mui/material/Button\";\nimport Dialog from \"@mui/material/Dialog\";\nimport DialogActions from \"@mui/material/DialogActions\";\nimport DialogContent from \"@mui/material/DialogContent\";\nimport DialogContentText from \"@mui/material/DialogContentText\";\nimport DialogTitle from \"@mui/material/DialogTitle\";\nimport React, { useState } from \"react\";\n\nexport function useConfirmationDialog() {\n  const [isOpen, setIsOpen] = useState(false);\n  const close = () => setIsOpen(false);\n  const open = () => setIsOpen(true);\n\n  return { open, close, isOpen };\n}\n\ninterface ConfirmationDialog {\n  isOpen: boolean;\n  onClose: () => void;\n  onConfirm: () => void;\n  children: React.ReactNode;\n}\n\nexport function ConfirmationDialog(props: ConfirmationDialog) {\n  const { onClose, onConfirm, isOpen, children } = props;\n\n  function confirm() {\n    onConfirm();\n    onClose();\n  }\n\n  return (\n    <Dialog\n      open={isOpen}\n      onClose={onClose}\n      aria-labelledby=\"alert-dialog-title\"\n      aria-describedby=\"alert-dialog-description\"\n    >\n      <DialogTitle id=\"alert-dialog-title\">Are you sure?</DialogTitle>\n      <DialogContent>\n        <DialogContentText id=\"alert-dialog-description\">{children}</DialogContentText>\n      </DialogContent>\n      <DialogActions>\n        <Button onClick={onClose}>Cancel</Button>\n        <Button onClick={confirm} autoFocus>\n          Confirm\n        </Button>\n      </DialogActions>\n    </Dialog>\n  );\n}\n"
  },
  {
    "path": "admin/src/lib/components/Editor.tsx",
    "content": "import MonacoEditor, { EditorProps } from \"@monaco-editor/react\";\n\nconst defaultMonacoOptions: EditorProps[\"options\"] = {\n  readOnly: true,\n  wordWrap: \"on\",\n  minimap: {\n    enabled: false,\n  },\n};\n\ntype language = \"html\" | \"typescript\" | \"json\";\n\nfunction languageForContentType(contentType?: string): language | undefined {\n  switch (contentType?.toLowerCase()) {\n    case \"text/html\":\n    case \"text/html; charset=utf-8\":\n      return \"html\";\n    case \"application/json\":\n    case \"application/json; charset=utf-8\":\n      return \"json\";\n    case \"application/javascript\":\n    case \"application/javascript; charset=utf-8\":\n      return \"typescript\";\n    default:\n      return;\n  }\n}\n\ninterface Props {\n  content: string;\n  contentType?: string;\n  monacoOptions?: EditorProps[\"options\"];\n  onChange?: EditorProps[\"onChange\"];\n}\n\nfunction Editor({ content, contentType, monacoOptions, onChange }: Props): JSX.Element {\n  return (\n    <MonacoEditor\n      language={languageForContentType(contentType)}\n      theme=\"vs-dark\"\n      options={{ ...defaultMonacoOptions, ...monacoOptions }}\n      value={content}\n      onChange={onChange}\n    />\n  );\n}\n\nexport default Editor;\n"
  },
  {
    "path": "admin/src/lib/components/HttpStatusIcon.tsx",
    "content": "import FiberManualRecordIcon from \"@mui/icons-material/FiberManualRecord\";\nimport { SvgIconTypeMap } from \"@mui/material\";\n\ninterface Props {\n  status: number;\n}\n\nexport default function HttpStatusIcon({ status }: Props): JSX.Element {\n  let color: SvgIconTypeMap[\"props\"][\"color\"] = \"inherit\";\n\n  switch (Math.floor(status / 100)) {\n    case 2:\n    case 3:\n      color = \"primary\";\n      break;\n    case 4:\n      color = \"warning\";\n      break;\n    case 5:\n      color = \"error\";\n      break;\n  }\n\n  return <FiberManualRecordIcon sx={{ marginTop: \"-.25rem\", verticalAlign: \"middle\" }} color={color} />;\n}\n"
  },
  {
    "path": "admin/src/lib/components/KeyValuePair.tsx",
    "content": "import ClearIcon from \"@mui/icons-material/Clear\";\nimport {\n  Alert,\n  IconButton,\n  InputBase,\n  InputBaseProps,\n  Snackbar,\n  styled,\n  Table,\n  TableBody,\n  TableCell,\n  TableContainer,\n  TableHead,\n  TableRow,\n  TableRowProps,\n} from \"@mui/material\";\nimport { useState } from \"react\";\n\nconst StyledInputBase = styled(InputBase)<InputBaseProps>(() => ({\n  fontSize: \"0.875rem\",\n  \"&.MuiInputBase-root input\": {\n    p: 0,\n  },\n}));\n\nconst StyledTableRow = styled(TableRow)<TableRowProps>(() => ({\n  \"& .delete-button\": {\n    visibility: \"hidden\",\n  },\n  \"&:hover .delete-button\": {\n    visibility: \"inherit\",\n  },\n}));\n\nexport interface KeyValuePair {\n  key: string;\n  value: string;\n}\n\nexport interface KeyValuePairTableProps {\n  items: KeyValuePair[];\n  onChange?: (key: string, value: string, index: number) => void;\n  onDelete?: (index: number) => void;\n}\n\nexport function KeyValuePairTable({ items, onChange, onDelete }: KeyValuePairTableProps): JSX.Element {\n  const [copyConfOpen, setCopyConfOpen] = useState(false);\n\n  const handleCellClick = (e: React.MouseEvent) => {\n    e.preventDefault();\n\n    const windowSel = window.getSelection();\n\n    if (!windowSel || !document) {\n      return;\n    }\n\n    const r = document.createRange();\n    r.selectNode(e.currentTarget);\n    windowSel.removeAllRanges();\n    windowSel.addRange(r);\n    document.execCommand(\"copy\");\n    windowSel.removeAllRanges();\n\n    setCopyConfOpen(true);\n  };\n\n  const handleCopyConfClose = (_: Event | React.SyntheticEvent, reason?: string) => {\n    if (reason === \"clickaway\") {\n      return;\n    }\n\n    setCopyConfOpen(false);\n  };\n\n  return (\n    <div>\n      <Snackbar open={copyConfOpen} autoHideDuration={3000} onClose={handleCopyConfClose}>\n        <Alert onClose={handleCopyConfClose} severity=\"info\">\n          Copied to clipboard.\n        </Alert>\n      </Snackbar>\n      <TableContainer sx={{ overflowX: \"initial\" }}>\n        <Table size=\"small\" stickyHeader>\n          <TableHead>\n            <TableRow>\n              <TableCell>Key</TableCell>\n              <TableCell>Value</TableCell>\n              {onDelete && <TableCell padding=\"checkbox\"></TableCell>}\n            </TableRow>\n          </TableHead>\n          <TableBody\n            sx={{\n              \"td, th, input\": {\n                fontFamily: \"'JetBrains Mono', monospace\",\n                fontSize: \"0.75rem\",\n                py: 0.2,\n              },\n              \"td span, th span\": {\n                display: \"block\",\n                py: 0.7,\n              },\n            }}\n          >\n            {items.map(({ key, value }, idx) => (\n              <StyledTableRow key={idx} hover>\n                <TableCell\n                  component=\"th\"\n                  scope=\"row\"\n                  onClick={(e) => {\n                    !onChange && handleCellClick(e);\n                  }}\n                  sx={{\n                    ...(!onChange && {\n                      \"&:hover\": {\n                        cursor: \"copy\",\n                      },\n                    }),\n                  }}\n                >\n                  {!onChange && <span>{key}</span>}\n                  {onChange && (\n                    <StyledInputBase\n                      size=\"small\"\n                      fullWidth\n                      placeholder=\"Key\"\n                      value={key}\n                      onChange={(e) => {\n                        onChange && onChange(e.target.value, value, idx);\n                      }}\n                    />\n                  )}\n                </TableCell>\n                <TableCell\n                  onClick={(e) => {\n                    !onChange && handleCellClick(e);\n                  }}\n                  sx={{\n                    width: \"60%\",\n                    wordBreak: \"break-all\",\n                    ...(!onChange && {\n                      \"&:hover\": {\n                        cursor: \"copy\",\n                      },\n                    }),\n                  }}\n                >\n                  {!onChange && value}\n                  {onChange && (\n                    <StyledInputBase\n                      size=\"small\"\n                      fullWidth\n                      placeholder=\"Value\"\n                      value={value}\n                      onChange={(e) => {\n                        onChange && onChange(key, e.target.value, idx);\n                      }}\n                    />\n                  )}\n                </TableCell>\n                {onDelete && (\n                  <TableCell>\n                    <div className=\"delete-button\">\n                      <IconButton\n                        size=\"small\"\n                        onClick={() => {\n                          onDelete && onDelete(idx);\n                        }}\n                        sx={{\n                          visibility: onDelete === undefined || items.length === idx + 1 ? \"hidden\" : \"inherit\",\n                        }}\n                      >\n                        <ClearIcon fontSize=\"inherit\" />\n                      </IconButton>\n                    </div>\n                  </TableCell>\n                )}\n              </StyledTableRow>\n            ))}\n          </TableBody>\n        </Table>\n      </TableContainer>\n    </div>\n  );\n}\n\nexport default KeyValuePairTable;\n"
  },
  {
    "path": "admin/src/lib/components/Link.tsx",
    "content": "import MuiLink, { LinkProps as MuiLinkProps } from \"@mui/material/Link\";\nimport { styled } from \"@mui/material/styles\";\nimport clsx from \"clsx\";\nimport NextLink, { LinkProps as NextLinkProps } from \"next/link\";\nimport { useRouter } from \"next/router\";\nimport * as React from \"react\";\n\n// Add support for the sx prop for consistency with the other branches.\nconst Anchor = styled(\"a\")({});\n\ninterface NextLinkComposedProps\n  extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, \"href\">,\n    Omit<NextLinkProps, \"href\" | \"as\"> {\n  to: NextLinkProps[\"href\"];\n  linkAs?: NextLinkProps[\"as\"];\n}\n\nexport const NextLinkComposed = React.forwardRef<HTMLAnchorElement, NextLinkComposedProps>(function NextLinkComposed(\n  props,\n  ref\n) {\n  const { to, linkAs, replace, scroll, shallow, prefetch, locale, ...other } = props;\n\n  return (\n    <NextLink\n      href={to}\n      prefetch={prefetch}\n      as={linkAs}\n      replace={replace}\n      scroll={scroll}\n      shallow={shallow}\n      passHref\n      locale={locale}\n    >\n      <Anchor ref={ref} {...other} />\n    </NextLink>\n  );\n});\n\nexport type LinkProps = {\n  activeClassName?: string;\n  as?: NextLinkProps[\"as\"];\n  href: NextLinkProps[\"href\"];\n  linkAs?: NextLinkProps[\"as\"]; // Useful when the as prop is shallow by styled().\n  noLinkStyle?: boolean;\n} & Omit<NextLinkComposedProps, \"to\" | \"linkAs\" | \"href\"> &\n  Omit<MuiLinkProps, \"href\">;\n\n// A styled version of the Next.js Link component:\n// https://nextjs.org/docs/api-reference/next/link\nconst Link = React.forwardRef<HTMLAnchorElement, LinkProps>(function Link(props, ref) {\n  const {\n    activeClassName = \"active\",\n    as,\n    className: classNameProps,\n    href,\n    linkAs: linkAsProp,\n    locale,\n    noLinkStyle,\n    prefetch,\n    replace,\n    role, // Link don't have roles.\n    scroll,\n    shallow,\n    ...other\n  } = props;\n\n  const router = useRouter();\n  const pathname = typeof href === \"string\" ? href : href.pathname;\n  const className = clsx(classNameProps, {\n    [activeClassName]: router.pathname === pathname && activeClassName,\n  });\n\n  const isExternal = typeof href === \"string\" && (href.indexOf(\"http\") === 0 || href.indexOf(\"mailto:\") === 0);\n\n  if (isExternal) {\n    if (noLinkStyle) {\n      return <Anchor className={className} href={href} ref={ref} {...other} />;\n    }\n\n    return <MuiLink className={className} href={href} ref={ref} {...other} />;\n  }\n\n  const linkAs = linkAsProp || as;\n  const nextjsProps = { to: href, linkAs, replace, scroll, shallow, prefetch, locale };\n\n  if (noLinkStyle) {\n    return <NextLinkComposed className={className} ref={ref} {...nextjsProps} {...other} />;\n  }\n\n  return <MuiLink component={NextLinkComposed} className={className} ref={ref} {...nextjsProps} {...other} />;\n});\n\nexport default Link;\n"
  },
  {
    "path": "admin/src/lib/components/RequestTabs.tsx",
    "content": "import { TabContext, TabList, TabPanel } from \"@mui/lab\";\nimport { Box, Tab } from \"@mui/material\";\nimport React, { useState } from \"react\";\n\nimport { KeyValuePairTable, KeyValuePair, KeyValuePairTableProps } from \"./KeyValuePair\";\n\nimport Editor from \"lib/components/Editor\";\n\nenum TabValue {\n  QueryParams = \"queryParams\",\n  Headers = \"headers\",\n  Body = \"body\",\n}\n\ninterface RequestTabsProps {\n  queryParams: KeyValuePair[];\n  headers: KeyValuePair[];\n  onQueryParamChange?: KeyValuePairTableProps[\"onChange\"];\n  onQueryParamDelete?: KeyValuePairTableProps[\"onDelete\"];\n  onHeaderChange?: KeyValuePairTableProps[\"onChange\"];\n  onHeaderDelete?: KeyValuePairTableProps[\"onDelete\"];\n  body?: string | null;\n  onBodyChange?: (value: string) => void;\n}\n\nfunction RequestTabs(props: RequestTabsProps): JSX.Element {\n  const {\n    queryParams,\n    onQueryParamChange,\n    onQueryParamDelete,\n    headers,\n    onHeaderChange,\n    onHeaderDelete,\n    body,\n    onBodyChange,\n  } = props;\n  const [tabValue, setTabValue] = useState(TabValue.QueryParams);\n\n  const tabSx = {\n    textTransform: \"none\",\n  };\n\n  const queryParamsLength = onQueryParamChange ? queryParams.length - 1 : queryParams.length;\n  const headersLength = onHeaderChange ? headers.length - 1 : headers.length;\n\n  return (\n    <Box sx={{ display: \"flex\", flexDirection: \"column\", height: \"100%\" }}>\n      <TabContext value={tabValue}>\n        <Box sx={{ borderBottom: 1, borderColor: \"divider\", mb: 1 }}>\n          <TabList onChange={(_, value) => setTabValue(value)}>\n            <Tab\n              value={TabValue.QueryParams}\n              label={\"Query Params\" + (queryParamsLength ? ` (${queryParamsLength})` : \"\")}\n              sx={tabSx}\n            />\n            <Tab value={TabValue.Headers} label={\"Headers\" + (headersLength ? ` (${headersLength})` : \"\")} sx={tabSx} />\n            <Tab\n              value={TabValue.Body}\n              label={\"Body\" + (body?.length ? ` (${body.length} byte` + (body.length > 1 ? \"s\" : \"\") + \")\" : \"\")}\n              sx={tabSx}\n            />\n          </TabList>\n        </Box>\n        <Box flex=\"1 auto\" overflow=\"scroll\" height=\"100%\">\n          <TabPanel value={TabValue.QueryParams} sx={{ p: 0, height: \"100%\" }}>\n            <Box>\n              <KeyValuePairTable items={queryParams} onChange={onQueryParamChange} onDelete={onQueryParamDelete} />\n            </Box>\n          </TabPanel>\n          <TabPanel value={TabValue.Headers} sx={{ p: 0, height: \"100%\" }}>\n            <Box>\n              <KeyValuePairTable items={headers} onChange={onHeaderChange} onDelete={onHeaderDelete} />\n            </Box>\n          </TabPanel>\n          <TabPanel value={TabValue.Body} sx={{ p: 0, height: \"100%\" }}>\n            <Editor\n              content={body || \"\"}\n              onChange={(value) => {\n                onBodyChange && onBodyChange(value || \"\");\n              }}\n              monacoOptions={{ readOnly: onBodyChange === undefined }}\n              contentType={headers.find(({ key }) => key.toLowerCase() === \"content-type\")?.value}\n            />\n          </TabPanel>\n        </Box>\n      </TabContext>\n    </Box>\n  );\n}\n\nexport default RequestTabs;\n"
  },
  {
    "path": "admin/src/lib/components/RequestsTable.tsx",
    "content": "import {\n  TableContainer,\n  Table,\n  TableHead,\n  TableRow,\n  TableCell,\n  TableBody,\n  styled,\n  TableCellProps,\n  TableRowProps,\n} from \"@mui/material\";\n\nimport HttpStatusIcon from \"./HttpStatusIcon\";\n\nimport { HttpMethod } from \"lib/graphql/generated\";\n\nconst baseCellStyle = {\n  whiteSpace: \"nowrap\",\n  overflow: \"hidden\",\n  textOverflow: \"ellipsis\",\n} as const;\n\nconst MethodTableCell = styled(TableCell)<TableCellProps>(() => ({\n  ...baseCellStyle,\n  width: \"100px\",\n}));\n\nconst OriginTableCell = styled(TableCell)<TableCellProps>(() => ({\n  ...baseCellStyle,\n  maxWidth: \"100px\",\n}));\n\nconst PathTableCell = styled(TableCell)<TableCellProps>(() => ({\n  ...baseCellStyle,\n  maxWidth: \"200px\",\n}));\n\nconst StatusTableCell = styled(TableCell)<TableCellProps>(() => ({\n  ...baseCellStyle,\n  width: \"100px\",\n}));\n\nconst RequestTableRow = styled(TableRow)<TableRowProps>(() => ({\n  \"&:hover\": {\n    cursor: \"pointer\",\n  },\n}));\n\ninterface HttpRequest {\n  id: string;\n  url: string;\n  method: HttpMethod;\n  response?: HttpResponse | null;\n}\n\ninterface HttpResponse {\n  statusCode: number;\n  statusReason: string;\n  body?: string;\n}\n\ninterface Props {\n  requests: HttpRequest[];\n  activeRowId?: string;\n  actionsCell?: (id: string) => JSX.Element;\n  onRowClick?: (id: string) => void;\n  onContextMenu?: (e: React.MouseEvent, id: string) => void;\n}\n\nexport default function RequestsTable(props: Props): JSX.Element {\n  const { requests, activeRowId, actionsCell, onRowClick, onContextMenu } = props;\n\n  return (\n    <TableContainer sx={{ overflowX: \"initial\" }}>\n      <Table size=\"small\" stickyHeader>\n        <TableHead>\n          <TableRow>\n            <TableCell>Method</TableCell>\n            <TableCell>Origin</TableCell>\n            <TableCell>Path</TableCell>\n            <TableCell>Status</TableCell>\n            {actionsCell && <TableCell padding=\"checkbox\"></TableCell>}\n          </TableRow>\n        </TableHead>\n        <TableBody>\n          {requests.map(({ id, method, url, response }) => {\n            const { origin, pathname, search, hash } = new URL(url);\n\n            return (\n              <RequestTableRow\n                key={id}\n                hover\n                selected={id === activeRowId}\n                onClick={() => {\n                  onRowClick && onRowClick(id);\n                }}\n                onContextMenu={(e) => {\n                  onContextMenu && onContextMenu(e, id);\n                }}\n              >\n                <MethodTableCell>\n                  <code>{method}</code>\n                </MethodTableCell>\n                <OriginTableCell>{origin}</OriginTableCell>\n                <PathTableCell>{decodeURIComponent(pathname + search + hash)}</PathTableCell>\n                <StatusTableCell>\n                  {response && <Status code={response.statusCode} reason={response.statusReason} />}\n                </StatusTableCell>\n                {actionsCell && actionsCell(id)}\n              </RequestTableRow>\n            );\n          })}\n        </TableBody>\n      </Table>\n    </TableContainer>\n  );\n}\n\nfunction Status({ code, reason }: { code: number; reason: string }): JSX.Element {\n  return (\n    <div>\n      <HttpStatusIcon status={code} />{\" \"}\n      <code>\n        {code} {reason}\n      </code>\n    </div>\n  );\n}\n"
  },
  {
    "path": "admin/src/lib/components/Response.tsx",
    "content": "import { Box, Typography } from \"@mui/material\";\n\nimport ResponseTabs from \"./ResponseTabs\";\n\nimport ResponseStatus from \"lib/components/ResponseStatus\";\nimport { HttpResponseLog } from \"lib/graphql/generated\";\n\ninterface ResponseProps {\n  response?: HttpResponseLog | null;\n}\n\nfunction Response({ response }: ResponseProps): JSX.Element {\n  return (\n    <Box height=\"100%\">\n      <Box sx={{ position: \"absolute\", right: 0, mt: 1.4 }}>\n        <Typography variant=\"overline\" color=\"textSecondary\" sx={{ float: \"right\", ml: 3 }}>\n          Response\n        </Typography>\n        {response && (\n          <Box sx={{ float: \"right\", mt: 0.2 }}>\n            <ResponseStatus\n              proto={response.proto}\n              statusCode={response.statusCode}\n              statusReason={response.statusReason}\n            />\n          </Box>\n        )}\n      </Box>\n      <ResponseTabs\n        body={response?.body}\n        headers={response?.headers || []}\n        hasResponse={response !== undefined && response !== null}\n      />\n    </Box>\n  );\n}\n\nexport default Response;\n"
  },
  {
    "path": "admin/src/lib/components/ResponseStatus.tsx",
    "content": "import { Typography } from \"@mui/material\";\n\nimport HttpStatusIcon from \"./HttpStatusIcon\";\n\nimport { HttpProtocol } from \"lib/graphql/generated\";\n\ntype ResponseStatusProps = {\n  proto: HttpProtocol;\n  statusCode: number;\n  statusReason: string;\n};\n\nfunction mapProto(proto: HttpProtocol): string {\n  switch (proto) {\n    case HttpProtocol.Http10:\n      return \"HTTP/1.0\";\n    case HttpProtocol.Http11:\n      return \"HTTP/1.1\";\n    case HttpProtocol.Http20:\n      return \"HTTP/2.0\";\n    default:\n      return proto;\n  }\n}\n\nexport default function ResponseStatus({ proto, statusCode, statusReason }: ResponseStatusProps): JSX.Element {\n  return (\n    <Typography variant=\"h6\" style={{ fontSize: \"1rem\", whiteSpace: \"nowrap\" }}>\n      <HttpStatusIcon status={statusCode} />{\" \"}\n      <Typography component=\"span\" color=\"textSecondary\">\n        <Typography component=\"span\" color=\"textSecondary\" style={{ fontFamily: \"'JetBrains Mono', monospace\" }}>\n          {mapProto(proto)}\n        </Typography>\n      </Typography>{\" \"}\n      {statusCode} {statusReason}\n    </Typography>\n  );\n}\n"
  },
  {
    "path": "admin/src/lib/components/ResponseTabs.tsx",
    "content": "import { TabContext, TabList, TabPanel } from \"@mui/lab\";\nimport { Box, Paper, Tab, Typography } from \"@mui/material\";\nimport React, { useState } from \"react\";\n\nimport { KeyValuePairTable, KeyValuePair, KeyValuePairTableProps } from \"./KeyValuePair\";\n\nimport Editor from \"lib/components/Editor\";\n\ninterface ResponseTabsProps {\n  headers: KeyValuePair[];\n  onHeaderChange?: KeyValuePairTableProps[\"onChange\"];\n  onHeaderDelete?: KeyValuePairTableProps[\"onDelete\"];\n  body?: string | null;\n  onBodyChange?: (value: string) => void;\n  hasResponse: boolean;\n}\n\nenum TabValue {\n  Body = \"body\",\n  Headers = \"headers\",\n}\n\nconst reqNotSent = (\n  <Paper variant=\"centered\">\n    <Typography>Response not received yet.</Typography>\n  </Paper>\n);\n\nfunction ResponseTabs(props: ResponseTabsProps): JSX.Element {\n  const { headers, onHeaderChange, onHeaderDelete, body, onBodyChange, hasResponse } = props;\n  const [tabValue, setTabValue] = useState(TabValue.Body);\n\n  const contentType = headers.find((header) => header.key.toLowerCase() === \"content-type\")?.value;\n\n  const tabSx = {\n    textTransform: \"none\",\n  };\n\n  const headersLength = onHeaderChange ? headers.length - 1 : headers.length;\n\n  return (\n    <Box height=\"100%\" sx={{ display: \"flex\", flexDirection: \"column\" }}>\n      <TabContext value={tabValue}>\n        <Box sx={{ borderBottom: 1, borderColor: \"divider\", mb: 1 }}>\n          <TabList onChange={(_, value) => setTabValue(value)}>\n            <Tab\n              value={TabValue.Body}\n              label={\"Body\" + (body?.length ? ` (${body.length} byte` + (body.length > 1 ? \"s\" : \"\") + \")\" : \"\")}\n              sx={tabSx}\n            />\n            <Tab value={TabValue.Headers} label={\"Headers\" + (headersLength ? ` (${headersLength})` : \"\")} sx={tabSx} />\n          </TabList>\n        </Box>\n        <Box flex=\"1 auto\" overflow=\"hidden\">\n          <TabPanel value={TabValue.Body} sx={{ p: 0, height: \"100%\" }}>\n            {hasResponse && (\n              <Editor\n                content={body || \"\"}\n                onChange={(value) => {\n                  onBodyChange && onBodyChange(value || \"\");\n                }}\n                monacoOptions={{ readOnly: onBodyChange === undefined }}\n                contentType={contentType}\n              />\n            )}\n            {!hasResponse && reqNotSent}\n          </TabPanel>\n          <TabPanel value={TabValue.Headers} sx={{ p: 0, height: \"100%\", overflow: \"scroll\" }}>\n            {hasResponse && <KeyValuePairTable items={headers} onChange={onHeaderChange} onDelete={onHeaderDelete} />}\n            {!hasResponse && reqNotSent}\n          </TabPanel>\n        </Box>\n      </TabContext>\n    </Box>\n  );\n}\n\nexport default ResponseTabs;\n"
  },
  {
    "path": "admin/src/lib/components/SplitPane.tsx",
    "content": "import { alpha, styled } from \"@mui/material/styles\";\nimport ReactSplitPane, { SplitPaneProps } from \"react-split-pane\";\n\nconst BORDER_WIDTH_FACTOR = 1.75;\nconst SIZE_FACTOR = 4;\nconst MARGIN_FACTOR = -1.75;\n\nconst SplitPane = styled(ReactSplitPane)<SplitPaneProps>(({ theme }) => ({\n  \".Resizer\": {\n    zIndex: theme.zIndex.mobileStepper,\n    boxSizing: \"border-box\",\n    backgroundClip: \"padding-box\",\n    backgroundColor: alpha(theme.palette.grey[400], 0.05),\n  },\n  \".Resizer:hover\": {\n    transition: \"all 0.5s ease\",\n    backgroundColor: alpha(theme.palette.primary.main, 1),\n  },\n\n  \".Resizer.horizontal\": {\n    height: theme.spacing(SIZE_FACTOR),\n    marginTop: theme.spacing(MARGIN_FACTOR),\n    marginBottom: theme.spacing(MARGIN_FACTOR),\n    borderTop: `${theme.spacing(BORDER_WIDTH_FACTOR)} solid rgba(255, 255, 255, 0)`,\n    borderBottom: `${theme.spacing(BORDER_WIDTH_FACTOR)} solid rgba(255, 255, 255, 0)`,\n    borderBottomColor: \"rgba(255, 255, 255, 0)\",\n    cursor: \"row-resize\",\n    width: \"100%\",\n  },\n\n  \".Resizer.vertical\": {\n    width: theme.spacing(SIZE_FACTOR),\n    marginLeft: theme.spacing(MARGIN_FACTOR),\n    marginRight: theme.spacing(MARGIN_FACTOR),\n    borderLeft: `${theme.spacing(BORDER_WIDTH_FACTOR)} solid rgba(255, 255, 255, 0)`,\n    borderRight: `${theme.spacing(BORDER_WIDTH_FACTOR)} solid rgba(255, 255, 255, 0)`,\n    cursor: \"col-resize\",\n  },\n\n  \".Resizer.disabled\": {\n    cursor: \"not-allowed\",\n  },\n\n  \".Resizer.disabled:hover\": {\n    borderColor: \"transparent\",\n  },\n\n  \".Pane\": {\n    overflow: \"hidden\",\n  },\n}));\n\nexport default SplitPane;\n"
  },
  {
    "path": "admin/src/lib/components/UrlBar.tsx",
    "content": "import { Box, BoxProps, FormControl, InputLabel, MenuItem, Select, TextField } from \"@mui/material\";\n\nimport { HttpProtocol } from \"lib/graphql/generated\";\n\nexport enum HttpMethod {\n  Get = \"GET\",\n  Post = \"POST\",\n  Put = \"PUT\",\n  Patch = \"PATCH\",\n  Delete = \"DELETE\",\n  Head = \"HEAD\",\n  Options = \"OPTIONS\",\n  Connect = \"CONNECT\",\n  Trace = \"TRACE\",\n}\n\nexport enum HttpProto {\n  Http10 = \"HTTP/1.0\",\n  Http11 = \"HTTP/1.1\",\n  Http20 = \"HTTP/2.0\",\n}\n\nexport const httpProtoMap = new Map([\n  [HttpProto.Http10, HttpProtocol.Http10],\n  [HttpProto.Http11, HttpProtocol.Http11],\n  [HttpProto.Http20, HttpProtocol.Http20],\n]);\n\ninterface UrlBarProps extends BoxProps {\n  method: HttpMethod;\n  onMethodChange?: (method: HttpMethod) => void;\n  url: string;\n  onUrlChange?: (url: string) => void;\n  proto: HttpProto;\n  onProtoChange?: (proto: HttpProto) => void;\n}\n\nfunction UrlBar(props: UrlBarProps) {\n  const { method, onMethodChange, url, onUrlChange, proto, onProtoChange, ...other } = props;\n\n  return (\n    <Box {...other} sx={{ ...other.sx, display: \"flex\" }}>\n      <FormControl>\n        <InputLabel id=\"req-method-label\">Method</InputLabel>\n        <Select\n          labelId=\"req-method-label\"\n          id=\"req-method\"\n          value={method}\n          label=\"Method\"\n          disabled={!onMethodChange}\n          onChange={(e) => onMethodChange && onMethodChange(e.target.value as HttpMethod)}\n          sx={{\n            width: \"8rem\",\n            \".MuiOutlinedInput-notchedOutline\": {\n              borderRightWidth: 0,\n              borderTopRightRadius: 0,\n              borderBottomRightRadius: 0,\n            },\n            \"&:hover .MuiOutlinedInput-notchedOutline\": {\n              borderRightWidth: 1,\n            },\n          }}\n        >\n          {Object.values(HttpMethod).map((method) => (\n            <MenuItem key={method} value={method}>\n              {method}\n            </MenuItem>\n          ))}\n        </Select>\n      </FormControl>\n      <TextField\n        label=\"URL\"\n        placeholder=\"E.g. “https://example.com/foobar”\"\n        value={url}\n        disabled={!onUrlChange}\n        onChange={(e) => onUrlChange && onUrlChange(e.target.value)}\n        required\n        variant=\"outlined\"\n        InputLabelProps={{\n          shrink: true,\n        }}\n        InputProps={{\n          sx: {\n            \".MuiOutlinedInput-notchedOutline\": {\n              borderRadius: 0,\n            },\n          },\n        }}\n        sx={{ flexGrow: 1 }}\n      />\n      <FormControl>\n        <InputLabel id=\"req-proto-label\">Protocol</InputLabel>\n        <Select\n          labelId=\"req-proto-label\"\n          id=\"req-proto\"\n          value={proto}\n          label=\"Protocol\"\n          disabled={!onProtoChange}\n          onChange={(e) => onProtoChange && onProtoChange(e.target.value as HttpProto)}\n          sx={{\n            \".MuiOutlinedInput-notchedOutline\": {\n              borderLeftWidth: 0,\n              borderTopLeftRadius: 0,\n              borderBottomLeftRadius: 0,\n            },\n            \"&:hover .MuiOutlinedInput-notchedOutline\": {\n              borderLeftWidth: 1,\n            },\n          }}\n        >\n          {Object.values(HttpProto).map((proto) => (\n            <MenuItem key={proto} value={proto}>\n              {proto}\n            </MenuItem>\n          ))}\n        </Select>\n      </FormControl>\n    </Box>\n  );\n}\n\nexport default UrlBar;\n"
  },
  {
    "path": "admin/src/lib/components/useContextMenu.tsx",
    "content": "import { Menu } from \"@mui/material\";\nimport React, { useState } from \"react\";\n\ninterface ContextMenuProps {\n  children?: React.ReactNode;\n}\n\nexport default function useContextMenu(): [\n  (props: ContextMenuProps) => JSX.Element,\n  (e: React.MouseEvent) => void,\n  () => void\n] {\n  const [contextMenu, setContextMenu] = useState<{\n    mouseX: number;\n    mouseY: number;\n  } | null>(null);\n\n  const handleContextMenu = (event: React.MouseEvent) => {\n    event.preventDefault();\n    setContextMenu(\n      contextMenu === null\n        ? {\n            mouseX: event.clientX - 2,\n            mouseY: event.clientY - 4,\n          }\n        : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu\n          // Other native context menus might behave different.\n          // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus.\n          null\n    );\n  };\n\n  const handleClose = () => {\n    setContextMenu(null);\n  };\n\n  const menu = ({ children }: ContextMenuProps): JSX.Element => (\n    <Menu\n      open={contextMenu !== null}\n      onClose={handleClose}\n      anchorReference=\"anchorPosition\"\n      anchorPosition={contextMenu !== null ? { top: contextMenu.mouseY, left: contextMenu.mouseX } : undefined}\n    >\n      {children}\n    </Menu>\n  );\n\n  return [menu, handleContextMenu, handleClose];\n}\n"
  },
  {
    "path": "admin/src/lib/graphql/generated.tsx",
    "content": "import { gql } from '@apollo/client';\nimport * as Apollo from '@apollo/client';\nexport type Maybe<T> = T | null;\nexport type InputMaybe<T> = Maybe<T>;\nexport type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };\nexport type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };\nexport type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };\nconst defaultOptions = {} as const;\n/** All built-in and custom scalars, mapped to their actual values */\nexport type Scalars = {\n  ID: string;\n  String: string;\n  Boolean: boolean;\n  Int: number;\n  Float: number;\n  Regexp: any;\n  Time: any;\n  URL: any;\n};\n\nexport type CancelRequestResult = {\n  __typename?: 'CancelRequestResult';\n  success: Scalars['Boolean'];\n};\n\nexport type CancelResponseResult = {\n  __typename?: 'CancelResponseResult';\n  success: Scalars['Boolean'];\n};\n\nexport type ClearHttpRequestLogResult = {\n  __typename?: 'ClearHTTPRequestLogResult';\n  success: Scalars['Boolean'];\n};\n\nexport type CloseProjectResult = {\n  __typename?: 'CloseProjectResult';\n  success: Scalars['Boolean'];\n};\n\nexport type DeleteProjectResult = {\n  __typename?: 'DeleteProjectResult';\n  success: Scalars['Boolean'];\n};\n\nexport type DeleteSenderRequestsResult = {\n  __typename?: 'DeleteSenderRequestsResult';\n  success: Scalars['Boolean'];\n};\n\nexport type HttpHeader = {\n  __typename?: 'HttpHeader';\n  key: Scalars['String'];\n  value: Scalars['String'];\n};\n\nexport type HttpHeaderInput = {\n  key: Scalars['String'];\n  value: Scalars['String'];\n};\n\nexport enum HttpMethod {\n  Connect = 'CONNECT',\n  Delete = 'DELETE',\n  Get = 'GET',\n  Head = 'HEAD',\n  Options = 'OPTIONS',\n  Patch = 'PATCH',\n  Post = 'POST',\n  Put = 'PUT',\n  Trace = 'TRACE'\n}\n\nexport enum HttpProtocol {\n  Http10 = 'HTTP10',\n  Http11 = 'HTTP11',\n  Http20 = 'HTTP20'\n}\n\nexport type HttpRequest = {\n  __typename?: 'HttpRequest';\n  body?: Maybe<Scalars['String']>;\n  headers: Array<HttpHeader>;\n  id: Scalars['ID'];\n  method: HttpMethod;\n  proto: HttpProtocol;\n  response?: Maybe<HttpResponse>;\n  url: Scalars['URL'];\n};\n\nexport type HttpRequestLog = {\n  __typename?: 'HttpRequestLog';\n  body?: Maybe<Scalars['String']>;\n  headers: Array<HttpHeader>;\n  id: Scalars['ID'];\n  method: HttpMethod;\n  proto: Scalars['String'];\n  response?: Maybe<HttpResponseLog>;\n  timestamp: Scalars['Time'];\n  url: Scalars['String'];\n};\n\nexport type HttpRequestLogFilter = {\n  __typename?: 'HttpRequestLogFilter';\n  onlyInScope: Scalars['Boolean'];\n  searchExpression?: Maybe<Scalars['String']>;\n};\n\nexport type HttpRequestLogFilterInput = {\n  onlyInScope?: InputMaybe<Scalars['Boolean']>;\n  searchExpression?: InputMaybe<Scalars['String']>;\n};\n\nexport type HttpResponse = {\n  __typename?: 'HttpResponse';\n  body?: Maybe<Scalars['String']>;\n  headers: Array<HttpHeader>;\n  /** Will be the same ID as its related request ID. */\n  id: Scalars['ID'];\n  proto: HttpProtocol;\n  statusCode: Scalars['Int'];\n  statusReason: Scalars['String'];\n};\n\nexport type HttpResponseLog = {\n  __typename?: 'HttpResponseLog';\n  body?: Maybe<Scalars['String']>;\n  headers: Array<HttpHeader>;\n  /** Will be the same ID as its related request ID. */\n  id: Scalars['ID'];\n  proto: HttpProtocol;\n  statusCode: Scalars['Int'];\n  statusReason: Scalars['String'];\n};\n\nexport type InterceptSettings = {\n  __typename?: 'InterceptSettings';\n  requestFilter?: Maybe<Scalars['String']>;\n  requestsEnabled: Scalars['Boolean'];\n  responseFilter?: Maybe<Scalars['String']>;\n  responsesEnabled: Scalars['Boolean'];\n};\n\nexport type ModifyRequestInput = {\n  body?: InputMaybe<Scalars['String']>;\n  headers?: InputMaybe<Array<HttpHeaderInput>>;\n  id: Scalars['ID'];\n  method: HttpMethod;\n  modifyResponse?: InputMaybe<Scalars['Boolean']>;\n  proto: HttpProtocol;\n  url: Scalars['URL'];\n};\n\nexport type ModifyRequestResult = {\n  __typename?: 'ModifyRequestResult';\n  success: Scalars['Boolean'];\n};\n\nexport type ModifyResponseInput = {\n  body?: InputMaybe<Scalars['String']>;\n  headers?: InputMaybe<Array<HttpHeaderInput>>;\n  proto: HttpProtocol;\n  requestID: Scalars['ID'];\n  statusCode: Scalars['Int'];\n  statusReason: Scalars['String'];\n};\n\nexport type ModifyResponseResult = {\n  __typename?: 'ModifyResponseResult';\n  success: Scalars['Boolean'];\n};\n\nexport type Mutation = {\n  __typename?: 'Mutation';\n  cancelRequest: CancelRequestResult;\n  cancelResponse: CancelResponseResult;\n  clearHTTPRequestLog: ClearHttpRequestLogResult;\n  closeProject: CloseProjectResult;\n  createOrUpdateSenderRequest: SenderRequest;\n  createProject?: Maybe<Project>;\n  createSenderRequestFromHttpRequestLog: SenderRequest;\n  deleteProject: DeleteProjectResult;\n  deleteSenderRequests: DeleteSenderRequestsResult;\n  modifyRequest: ModifyRequestResult;\n  modifyResponse: ModifyResponseResult;\n  openProject?: Maybe<Project>;\n  sendRequest: SenderRequest;\n  setHttpRequestLogFilter?: Maybe<HttpRequestLogFilter>;\n  setScope: Array<ScopeRule>;\n  setSenderRequestFilter?: Maybe<SenderRequestFilter>;\n  updateInterceptSettings: InterceptSettings;\n};\n\n\nexport type MutationCancelRequestArgs = {\n  id: Scalars['ID'];\n};\n\n\nexport type MutationCancelResponseArgs = {\n  requestID: Scalars['ID'];\n};\n\n\nexport type MutationCreateOrUpdateSenderRequestArgs = {\n  request: SenderRequestInput;\n};\n\n\nexport type MutationCreateProjectArgs = {\n  name: Scalars['String'];\n};\n\n\nexport type MutationCreateSenderRequestFromHttpRequestLogArgs = {\n  id: Scalars['ID'];\n};\n\n\nexport type MutationDeleteProjectArgs = {\n  id: Scalars['ID'];\n};\n\n\nexport type MutationModifyRequestArgs = {\n  request: ModifyRequestInput;\n};\n\n\nexport type MutationModifyResponseArgs = {\n  response: ModifyResponseInput;\n};\n\n\nexport type MutationOpenProjectArgs = {\n  id: Scalars['ID'];\n};\n\n\nexport type MutationSendRequestArgs = {\n  id: Scalars['ID'];\n};\n\n\nexport type MutationSetHttpRequestLogFilterArgs = {\n  filter?: InputMaybe<HttpRequestLogFilterInput>;\n};\n\n\nexport type MutationSetScopeArgs = {\n  scope: Array<ScopeRuleInput>;\n};\n\n\nexport type MutationSetSenderRequestFilterArgs = {\n  filter?: InputMaybe<SenderRequestFilterInput>;\n};\n\n\nexport type MutationUpdateInterceptSettingsArgs = {\n  input: UpdateInterceptSettingsInput;\n};\n\nexport type Project = {\n  __typename?: 'Project';\n  id: Scalars['ID'];\n  isActive: Scalars['Boolean'];\n  name: Scalars['String'];\n  settings: ProjectSettings;\n};\n\nexport type ProjectSettings = {\n  __typename?: 'ProjectSettings';\n  intercept: InterceptSettings;\n};\n\nexport type Query = {\n  __typename?: 'Query';\n  activeProject?: Maybe<Project>;\n  httpRequestLog?: Maybe<HttpRequestLog>;\n  httpRequestLogFilter?: Maybe<HttpRequestLogFilter>;\n  httpRequestLogs: Array<HttpRequestLog>;\n  interceptedRequest?: Maybe<HttpRequest>;\n  interceptedRequests: Array<HttpRequest>;\n  projects: Array<Project>;\n  scope: Array<ScopeRule>;\n  senderRequest?: Maybe<SenderRequest>;\n  senderRequests: Array<SenderRequest>;\n};\n\n\nexport type QueryHttpRequestLogArgs = {\n  id: Scalars['ID'];\n};\n\n\nexport type QueryInterceptedRequestArgs = {\n  id: Scalars['ID'];\n};\n\n\nexport type QuerySenderRequestArgs = {\n  id: Scalars['ID'];\n};\n\nexport type ScopeHeader = {\n  __typename?: 'ScopeHeader';\n  key?: Maybe<Scalars['Regexp']>;\n  value?: Maybe<Scalars['Regexp']>;\n};\n\nexport type ScopeHeaderInput = {\n  key?: InputMaybe<Scalars['Regexp']>;\n  value?: InputMaybe<Scalars['Regexp']>;\n};\n\nexport type ScopeRule = {\n  __typename?: 'ScopeRule';\n  body?: Maybe<Scalars['Regexp']>;\n  header?: Maybe<ScopeHeader>;\n  url?: Maybe<Scalars['Regexp']>;\n};\n\nexport type ScopeRuleInput = {\n  body?: InputMaybe<Scalars['Regexp']>;\n  header?: InputMaybe<ScopeHeaderInput>;\n  url?: InputMaybe<Scalars['Regexp']>;\n};\n\nexport type SenderRequest = {\n  __typename?: 'SenderRequest';\n  body?: Maybe<Scalars['String']>;\n  headers?: Maybe<Array<HttpHeader>>;\n  id: Scalars['ID'];\n  method: HttpMethod;\n  proto: HttpProtocol;\n  response?: Maybe<HttpResponseLog>;\n  sourceRequestLogID?: Maybe<Scalars['ID']>;\n  timestamp: Scalars['Time'];\n  url: Scalars['URL'];\n};\n\nexport type SenderRequestFilter = {\n  __typename?: 'SenderRequestFilter';\n  onlyInScope: Scalars['Boolean'];\n  searchExpression?: Maybe<Scalars['String']>;\n};\n\nexport type SenderRequestFilterInput = {\n  onlyInScope?: InputMaybe<Scalars['Boolean']>;\n  searchExpression?: InputMaybe<Scalars['String']>;\n};\n\nexport type SenderRequestInput = {\n  body?: InputMaybe<Scalars['String']>;\n  headers?: InputMaybe<Array<HttpHeaderInput>>;\n  id?: InputMaybe<Scalars['ID']>;\n  method?: InputMaybe<HttpMethod>;\n  proto?: InputMaybe<HttpProtocol>;\n  url: Scalars['URL'];\n};\n\nexport type UpdateInterceptSettingsInput = {\n  requestFilter?: InputMaybe<Scalars['String']>;\n  requestsEnabled: Scalars['Boolean'];\n  responseFilter?: InputMaybe<Scalars['String']>;\n  responsesEnabled: Scalars['Boolean'];\n};\n\nexport type CancelRequestMutationVariables = Exact<{\n  id: Scalars['ID'];\n}>;\n\n\nexport type CancelRequestMutation = { __typename?: 'Mutation', cancelRequest: { __typename?: 'CancelRequestResult', success: boolean } };\n\nexport type CancelResponseMutationVariables = Exact<{\n  requestID: Scalars['ID'];\n}>;\n\n\nexport type CancelResponseMutation = { __typename?: 'Mutation', cancelResponse: { __typename?: 'CancelResponseResult', success: boolean } };\n\nexport type GetInterceptedRequestQueryVariables = Exact<{\n  id: Scalars['ID'];\n}>;\n\n\nexport type GetInterceptedRequestQuery = { __typename?: 'Query', interceptedRequest?: { __typename?: 'HttpRequest', id: string, url: any, method: HttpMethod, proto: HttpProtocol, body?: string | null, headers: Array<{ __typename?: 'HttpHeader', key: string, value: string }>, response?: { __typename?: 'HttpResponse', id: string, proto: HttpProtocol, statusCode: number, statusReason: string, body?: string | null, headers: Array<{ __typename?: 'HttpHeader', key: string, value: string }> } | null } | null };\n\nexport type ModifyRequestMutationVariables = Exact<{\n  request: ModifyRequestInput;\n}>;\n\n\nexport type ModifyRequestMutation = { __typename?: 'Mutation', modifyRequest: { __typename?: 'ModifyRequestResult', success: boolean } };\n\nexport type ModifyResponseMutationVariables = Exact<{\n  response: ModifyResponseInput;\n}>;\n\n\nexport type ModifyResponseMutation = { __typename?: 'Mutation', modifyResponse: { __typename?: 'ModifyResponseResult', success: boolean } };\n\nexport type ActiveProjectQueryVariables = Exact<{ [key: string]: never; }>;\n\n\nexport type ActiveProjectQuery = { __typename?: 'Query', activeProject?: { __typename?: 'Project', id: string, name: string, isActive: boolean, settings: { __typename?: 'ProjectSettings', intercept: { __typename?: 'InterceptSettings', requestsEnabled: boolean, responsesEnabled: boolean, requestFilter?: string | null, responseFilter?: string | null } } } | null };\n\nexport type CloseProjectMutationVariables = Exact<{ [key: string]: never; }>;\n\n\nexport type CloseProjectMutation = { __typename?: 'Mutation', closeProject: { __typename?: 'CloseProjectResult', success: boolean } };\n\nexport type CreateProjectMutationVariables = Exact<{\n  name: Scalars['String'];\n}>;\n\n\nexport type CreateProjectMutation = { __typename?: 'Mutation', createProject?: { __typename?: 'Project', id: string, name: string } | null };\n\nexport type DeleteProjectMutationVariables = Exact<{\n  id: Scalars['ID'];\n}>;\n\n\nexport type DeleteProjectMutation = { __typename?: 'Mutation', deleteProject: { __typename?: 'DeleteProjectResult', success: boolean } };\n\nexport type OpenProjectMutationVariables = Exact<{\n  id: Scalars['ID'];\n}>;\n\n\nexport type OpenProjectMutation = { __typename?: 'Mutation', openProject?: { __typename?: 'Project', id: string, name: string, isActive: boolean } | null };\n\nexport type ProjectsQueryVariables = Exact<{ [key: string]: never; }>;\n\n\nexport type ProjectsQuery = { __typename?: 'Query', projects: Array<{ __typename?: 'Project', id: string, name: string, isActive: boolean }> };\n\nexport type ClearHttpRequestLogMutationVariables = Exact<{ [key: string]: never; }>;\n\n\nexport type ClearHttpRequestLogMutation = { __typename?: 'Mutation', clearHTTPRequestLog: { __typename?: 'ClearHTTPRequestLogResult', success: boolean } };\n\nexport type HttpRequestLogQueryVariables = Exact<{\n  id: Scalars['ID'];\n}>;\n\n\nexport type HttpRequestLogQuery = { __typename?: 'Query', httpRequestLog?: { __typename?: 'HttpRequestLog', id: string, method: HttpMethod, url: string, proto: string, body?: string | null, headers: Array<{ __typename?: 'HttpHeader', key: string, value: string }>, response?: { __typename?: 'HttpResponseLog', id: string, proto: HttpProtocol, statusCode: number, statusReason: string, body?: string | null, headers: Array<{ __typename?: 'HttpHeader', key: string, value: string }> } | null } | null };\n\nexport type HttpRequestLogFilterQueryVariables = Exact<{ [key: string]: never; }>;\n\n\nexport type HttpRequestLogFilterQuery = { __typename?: 'Query', httpRequestLogFilter?: { __typename?: 'HttpRequestLogFilter', onlyInScope: boolean, searchExpression?: string | null } | null };\n\nexport type HttpRequestLogsQueryVariables = Exact<{ [key: string]: never; }>;\n\n\nexport type HttpRequestLogsQuery = { __typename?: 'Query', httpRequestLogs: Array<{ __typename?: 'HttpRequestLog', id: string, method: HttpMethod, url: string, timestamp: any, response?: { __typename?: 'HttpResponseLog', statusCode: number, statusReason: string } | null }> };\n\nexport type SetHttpRequestLogFilterMutationVariables = Exact<{\n  filter?: InputMaybe<HttpRequestLogFilterInput>;\n}>;\n\n\nexport type SetHttpRequestLogFilterMutation = { __typename?: 'Mutation', setHttpRequestLogFilter?: { __typename?: 'HttpRequestLogFilter', onlyInScope: boolean, searchExpression?: string | null } | null };\n\nexport type ScopeQueryVariables = Exact<{ [key: string]: never; }>;\n\n\nexport type ScopeQuery = { __typename?: 'Query', scope: Array<{ __typename?: 'ScopeRule', url?: any | null }> };\n\nexport type SetScopeMutationVariables = Exact<{\n  scope: Array<ScopeRuleInput> | ScopeRuleInput;\n}>;\n\n\nexport type SetScopeMutation = { __typename?: 'Mutation', setScope: Array<{ __typename?: 'ScopeRule', url?: any | null }> };\n\nexport type CreateOrUpdateSenderRequestMutationVariables = Exact<{\n  request: SenderRequestInput;\n}>;\n\n\nexport type CreateOrUpdateSenderRequestMutation = { __typename?: 'Mutation', createOrUpdateSenderRequest: { __typename?: 'SenderRequest', id: string } };\n\nexport type CreateSenderRequestFromHttpRequestLogMutationVariables = Exact<{\n  id: Scalars['ID'];\n}>;\n\n\nexport type CreateSenderRequestFromHttpRequestLogMutation = { __typename?: 'Mutation', createSenderRequestFromHttpRequestLog: { __typename?: 'SenderRequest', id: string } };\n\nexport type SendRequestMutationVariables = Exact<{\n  id: Scalars['ID'];\n}>;\n\n\nexport type SendRequestMutation = { __typename?: 'Mutation', sendRequest: { __typename?: 'SenderRequest', id: string } };\n\nexport type GetSenderRequestQueryVariables = Exact<{\n  id: Scalars['ID'];\n}>;\n\n\nexport type GetSenderRequestQuery = { __typename?: 'Query', senderRequest?: { __typename?: 'SenderRequest', id: string, sourceRequestLogID?: string | null, url: any, method: HttpMethod, proto: HttpProtocol, body?: string | null, timestamp: any, headers?: Array<{ __typename?: 'HttpHeader', key: string, value: string }> | null, response?: { __typename?: 'HttpResponseLog', id: string, proto: HttpProtocol, statusCode: number, statusReason: string, body?: string | null, headers: Array<{ __typename?: 'HttpHeader', key: string, value: string }> } | null } | null };\n\nexport type GetSenderRequestsQueryVariables = Exact<{ [key: string]: never; }>;\n\n\nexport type GetSenderRequestsQuery = { __typename?: 'Query', senderRequests: Array<{ __typename?: 'SenderRequest', id: string, url: any, method: HttpMethod, response?: { __typename?: 'HttpResponseLog', id: string, statusCode: number, statusReason: string } | null }> };\n\nexport type UpdateInterceptSettingsMutationVariables = Exact<{\n  input: UpdateInterceptSettingsInput;\n}>;\n\n\nexport type UpdateInterceptSettingsMutation = { __typename?: 'Mutation', updateInterceptSettings: { __typename?: 'InterceptSettings', requestsEnabled: boolean, responsesEnabled: boolean, requestFilter?: string | null, responseFilter?: string | null } };\n\nexport type GetInterceptedRequestsQueryVariables = Exact<{ [key: string]: never; }>;\n\n\nexport type GetInterceptedRequestsQuery = { __typename?: 'Query', interceptedRequests: Array<{ __typename?: 'HttpRequest', id: string, url: any, method: HttpMethod, response?: { __typename?: 'HttpResponse', statusCode: number, statusReason: string } | null }> };\n\n\nexport const CancelRequestDocument = gql`\n    mutation CancelRequest($id: ID!) {\n  cancelRequest(id: $id) {\n    success\n  }\n}\n    `;\nexport type CancelRequestMutationFn = Apollo.MutationFunction<CancelRequestMutation, CancelRequestMutationVariables>;\n\n/**\n * __useCancelRequestMutation__\n *\n * To run a mutation, you first call `useCancelRequestMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useCancelRequestMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [cancelRequestMutation, { data, loading, error }] = useCancelRequestMutation({\n *   variables: {\n *      id: // value for 'id'\n *   },\n * });\n */\nexport function useCancelRequestMutation(baseOptions?: Apollo.MutationHookOptions<CancelRequestMutation, CancelRequestMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<CancelRequestMutation, CancelRequestMutationVariables>(CancelRequestDocument, options);\n      }\nexport type CancelRequestMutationHookResult = ReturnType<typeof useCancelRequestMutation>;\nexport type CancelRequestMutationResult = Apollo.MutationResult<CancelRequestMutation>;\nexport type CancelRequestMutationOptions = Apollo.BaseMutationOptions<CancelRequestMutation, CancelRequestMutationVariables>;\nexport const CancelResponseDocument = gql`\n    mutation CancelResponse($requestID: ID!) {\n  cancelResponse(requestID: $requestID) {\n    success\n  }\n}\n    `;\nexport type CancelResponseMutationFn = Apollo.MutationFunction<CancelResponseMutation, CancelResponseMutationVariables>;\n\n/**\n * __useCancelResponseMutation__\n *\n * To run a mutation, you first call `useCancelResponseMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useCancelResponseMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [cancelResponseMutation, { data, loading, error }] = useCancelResponseMutation({\n *   variables: {\n *      requestID: // value for 'requestID'\n *   },\n * });\n */\nexport function useCancelResponseMutation(baseOptions?: Apollo.MutationHookOptions<CancelResponseMutation, CancelResponseMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<CancelResponseMutation, CancelResponseMutationVariables>(CancelResponseDocument, options);\n      }\nexport type CancelResponseMutationHookResult = ReturnType<typeof useCancelResponseMutation>;\nexport type CancelResponseMutationResult = Apollo.MutationResult<CancelResponseMutation>;\nexport type CancelResponseMutationOptions = Apollo.BaseMutationOptions<CancelResponseMutation, CancelResponseMutationVariables>;\nexport const GetInterceptedRequestDocument = gql`\n    query GetInterceptedRequest($id: ID!) {\n  interceptedRequest(id: $id) {\n    id\n    url\n    method\n    proto\n    headers {\n      key\n      value\n    }\n    body\n    response {\n      id\n      proto\n      statusCode\n      statusReason\n      headers {\n        key\n        value\n      }\n      body\n    }\n  }\n}\n    `;\n\n/**\n * __useGetInterceptedRequestQuery__\n *\n * To run a query within a React component, call `useGetInterceptedRequestQuery` and pass it any options that fit your needs.\n * When your component renders, `useGetInterceptedRequestQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useGetInterceptedRequestQuery({\n *   variables: {\n *      id: // value for 'id'\n *   },\n * });\n */\nexport function useGetInterceptedRequestQuery(baseOptions: Apollo.QueryHookOptions<GetInterceptedRequestQuery, GetInterceptedRequestQueryVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useQuery<GetInterceptedRequestQuery, GetInterceptedRequestQueryVariables>(GetInterceptedRequestDocument, options);\n      }\nexport function useGetInterceptedRequestLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetInterceptedRequestQuery, GetInterceptedRequestQueryVariables>) {\n          const options = {...defaultOptions, ...baseOptions}\n          return Apollo.useLazyQuery<GetInterceptedRequestQuery, GetInterceptedRequestQueryVariables>(GetInterceptedRequestDocument, options);\n        }\nexport type GetInterceptedRequestQueryHookResult = ReturnType<typeof useGetInterceptedRequestQuery>;\nexport type GetInterceptedRequestLazyQueryHookResult = ReturnType<typeof useGetInterceptedRequestLazyQuery>;\nexport type GetInterceptedRequestQueryResult = Apollo.QueryResult<GetInterceptedRequestQuery, GetInterceptedRequestQueryVariables>;\nexport const ModifyRequestDocument = gql`\n    mutation ModifyRequest($request: ModifyRequestInput!) {\n  modifyRequest(request: $request) {\n    success\n  }\n}\n    `;\nexport type ModifyRequestMutationFn = Apollo.MutationFunction<ModifyRequestMutation, ModifyRequestMutationVariables>;\n\n/**\n * __useModifyRequestMutation__\n *\n * To run a mutation, you first call `useModifyRequestMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useModifyRequestMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [modifyRequestMutation, { data, loading, error }] = useModifyRequestMutation({\n *   variables: {\n *      request: // value for 'request'\n *   },\n * });\n */\nexport function useModifyRequestMutation(baseOptions?: Apollo.MutationHookOptions<ModifyRequestMutation, ModifyRequestMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<ModifyRequestMutation, ModifyRequestMutationVariables>(ModifyRequestDocument, options);\n      }\nexport type ModifyRequestMutationHookResult = ReturnType<typeof useModifyRequestMutation>;\nexport type ModifyRequestMutationResult = Apollo.MutationResult<ModifyRequestMutation>;\nexport type ModifyRequestMutationOptions = Apollo.BaseMutationOptions<ModifyRequestMutation, ModifyRequestMutationVariables>;\nexport const ModifyResponseDocument = gql`\n    mutation ModifyResponse($response: ModifyResponseInput!) {\n  modifyResponse(response: $response) {\n    success\n  }\n}\n    `;\nexport type ModifyResponseMutationFn = Apollo.MutationFunction<ModifyResponseMutation, ModifyResponseMutationVariables>;\n\n/**\n * __useModifyResponseMutation__\n *\n * To run a mutation, you first call `useModifyResponseMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useModifyResponseMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [modifyResponseMutation, { data, loading, error }] = useModifyResponseMutation({\n *   variables: {\n *      response: // value for 'response'\n *   },\n * });\n */\nexport function useModifyResponseMutation(baseOptions?: Apollo.MutationHookOptions<ModifyResponseMutation, ModifyResponseMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<ModifyResponseMutation, ModifyResponseMutationVariables>(ModifyResponseDocument, options);\n      }\nexport type ModifyResponseMutationHookResult = ReturnType<typeof useModifyResponseMutation>;\nexport type ModifyResponseMutationResult = Apollo.MutationResult<ModifyResponseMutation>;\nexport type ModifyResponseMutationOptions = Apollo.BaseMutationOptions<ModifyResponseMutation, ModifyResponseMutationVariables>;\nexport const ActiveProjectDocument = gql`\n    query ActiveProject {\n  activeProject {\n    id\n    name\n    isActive\n    settings {\n      intercept {\n        requestsEnabled\n        responsesEnabled\n        requestFilter\n        responseFilter\n      }\n    }\n  }\n}\n    `;\n\n/**\n * __useActiveProjectQuery__\n *\n * To run a query within a React component, call `useActiveProjectQuery` and pass it any options that fit your needs.\n * When your component renders, `useActiveProjectQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useActiveProjectQuery({\n *   variables: {\n *   },\n * });\n */\nexport function useActiveProjectQuery(baseOptions?: Apollo.QueryHookOptions<ActiveProjectQuery, ActiveProjectQueryVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useQuery<ActiveProjectQuery, ActiveProjectQueryVariables>(ActiveProjectDocument, options);\n      }\nexport function useActiveProjectLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ActiveProjectQuery, ActiveProjectQueryVariables>) {\n          const options = {...defaultOptions, ...baseOptions}\n          return Apollo.useLazyQuery<ActiveProjectQuery, ActiveProjectQueryVariables>(ActiveProjectDocument, options);\n        }\nexport type ActiveProjectQueryHookResult = ReturnType<typeof useActiveProjectQuery>;\nexport type ActiveProjectLazyQueryHookResult = ReturnType<typeof useActiveProjectLazyQuery>;\nexport type ActiveProjectQueryResult = Apollo.QueryResult<ActiveProjectQuery, ActiveProjectQueryVariables>;\nexport const CloseProjectDocument = gql`\n    mutation CloseProject {\n  closeProject {\n    success\n  }\n}\n    `;\nexport type CloseProjectMutationFn = Apollo.MutationFunction<CloseProjectMutation, CloseProjectMutationVariables>;\n\n/**\n * __useCloseProjectMutation__\n *\n * To run a mutation, you first call `useCloseProjectMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useCloseProjectMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [closeProjectMutation, { data, loading, error }] = useCloseProjectMutation({\n *   variables: {\n *   },\n * });\n */\nexport function useCloseProjectMutation(baseOptions?: Apollo.MutationHookOptions<CloseProjectMutation, CloseProjectMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<CloseProjectMutation, CloseProjectMutationVariables>(CloseProjectDocument, options);\n      }\nexport type CloseProjectMutationHookResult = ReturnType<typeof useCloseProjectMutation>;\nexport type CloseProjectMutationResult = Apollo.MutationResult<CloseProjectMutation>;\nexport type CloseProjectMutationOptions = Apollo.BaseMutationOptions<CloseProjectMutation, CloseProjectMutationVariables>;\nexport const CreateProjectDocument = gql`\n    mutation CreateProject($name: String!) {\n  createProject(name: $name) {\n    id\n    name\n  }\n}\n    `;\nexport type CreateProjectMutationFn = Apollo.MutationFunction<CreateProjectMutation, CreateProjectMutationVariables>;\n\n/**\n * __useCreateProjectMutation__\n *\n * To run a mutation, you first call `useCreateProjectMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useCreateProjectMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [createProjectMutation, { data, loading, error }] = useCreateProjectMutation({\n *   variables: {\n *      name: // value for 'name'\n *   },\n * });\n */\nexport function useCreateProjectMutation(baseOptions?: Apollo.MutationHookOptions<CreateProjectMutation, CreateProjectMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<CreateProjectMutation, CreateProjectMutationVariables>(CreateProjectDocument, options);\n      }\nexport type CreateProjectMutationHookResult = ReturnType<typeof useCreateProjectMutation>;\nexport type CreateProjectMutationResult = Apollo.MutationResult<CreateProjectMutation>;\nexport type CreateProjectMutationOptions = Apollo.BaseMutationOptions<CreateProjectMutation, CreateProjectMutationVariables>;\nexport const DeleteProjectDocument = gql`\n    mutation DeleteProject($id: ID!) {\n  deleteProject(id: $id) {\n    success\n  }\n}\n    `;\nexport type DeleteProjectMutationFn = Apollo.MutationFunction<DeleteProjectMutation, DeleteProjectMutationVariables>;\n\n/**\n * __useDeleteProjectMutation__\n *\n * To run a mutation, you first call `useDeleteProjectMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useDeleteProjectMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [deleteProjectMutation, { data, loading, error }] = useDeleteProjectMutation({\n *   variables: {\n *      id: // value for 'id'\n *   },\n * });\n */\nexport function useDeleteProjectMutation(baseOptions?: Apollo.MutationHookOptions<DeleteProjectMutation, DeleteProjectMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<DeleteProjectMutation, DeleteProjectMutationVariables>(DeleteProjectDocument, options);\n      }\nexport type DeleteProjectMutationHookResult = ReturnType<typeof useDeleteProjectMutation>;\nexport type DeleteProjectMutationResult = Apollo.MutationResult<DeleteProjectMutation>;\nexport type DeleteProjectMutationOptions = Apollo.BaseMutationOptions<DeleteProjectMutation, DeleteProjectMutationVariables>;\nexport const OpenProjectDocument = gql`\n    mutation OpenProject($id: ID!) {\n  openProject(id: $id) {\n    id\n    name\n    isActive\n  }\n}\n    `;\nexport type OpenProjectMutationFn = Apollo.MutationFunction<OpenProjectMutation, OpenProjectMutationVariables>;\n\n/**\n * __useOpenProjectMutation__\n *\n * To run a mutation, you first call `useOpenProjectMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useOpenProjectMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [openProjectMutation, { data, loading, error }] = useOpenProjectMutation({\n *   variables: {\n *      id: // value for 'id'\n *   },\n * });\n */\nexport function useOpenProjectMutation(baseOptions?: Apollo.MutationHookOptions<OpenProjectMutation, OpenProjectMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<OpenProjectMutation, OpenProjectMutationVariables>(OpenProjectDocument, options);\n      }\nexport type OpenProjectMutationHookResult = ReturnType<typeof useOpenProjectMutation>;\nexport type OpenProjectMutationResult = Apollo.MutationResult<OpenProjectMutation>;\nexport type OpenProjectMutationOptions = Apollo.BaseMutationOptions<OpenProjectMutation, OpenProjectMutationVariables>;\nexport const ProjectsDocument = gql`\n    query Projects {\n  projects {\n    id\n    name\n    isActive\n  }\n}\n    `;\n\n/**\n * __useProjectsQuery__\n *\n * To run a query within a React component, call `useProjectsQuery` and pass it any options that fit your needs.\n * When your component renders, `useProjectsQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useProjectsQuery({\n *   variables: {\n *   },\n * });\n */\nexport function useProjectsQuery(baseOptions?: Apollo.QueryHookOptions<ProjectsQuery, ProjectsQueryVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useQuery<ProjectsQuery, ProjectsQueryVariables>(ProjectsDocument, options);\n      }\nexport function useProjectsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ProjectsQuery, ProjectsQueryVariables>) {\n          const options = {...defaultOptions, ...baseOptions}\n          return Apollo.useLazyQuery<ProjectsQuery, ProjectsQueryVariables>(ProjectsDocument, options);\n        }\nexport type ProjectsQueryHookResult = ReturnType<typeof useProjectsQuery>;\nexport type ProjectsLazyQueryHookResult = ReturnType<typeof useProjectsLazyQuery>;\nexport type ProjectsQueryResult = Apollo.QueryResult<ProjectsQuery, ProjectsQueryVariables>;\nexport const ClearHttpRequestLogDocument = gql`\n    mutation ClearHTTPRequestLog {\n  clearHTTPRequestLog {\n    success\n  }\n}\n    `;\nexport type ClearHttpRequestLogMutationFn = Apollo.MutationFunction<ClearHttpRequestLogMutation, ClearHttpRequestLogMutationVariables>;\n\n/**\n * __useClearHttpRequestLogMutation__\n *\n * To run a mutation, you first call `useClearHttpRequestLogMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useClearHttpRequestLogMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [clearHttpRequestLogMutation, { data, loading, error }] = useClearHttpRequestLogMutation({\n *   variables: {\n *   },\n * });\n */\nexport function useClearHttpRequestLogMutation(baseOptions?: Apollo.MutationHookOptions<ClearHttpRequestLogMutation, ClearHttpRequestLogMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<ClearHttpRequestLogMutation, ClearHttpRequestLogMutationVariables>(ClearHttpRequestLogDocument, options);\n      }\nexport type ClearHttpRequestLogMutationHookResult = ReturnType<typeof useClearHttpRequestLogMutation>;\nexport type ClearHttpRequestLogMutationResult = Apollo.MutationResult<ClearHttpRequestLogMutation>;\nexport type ClearHttpRequestLogMutationOptions = Apollo.BaseMutationOptions<ClearHttpRequestLogMutation, ClearHttpRequestLogMutationVariables>;\nexport const HttpRequestLogDocument = gql`\n    query HttpRequestLog($id: ID!) {\n  httpRequestLog(id: $id) {\n    id\n    method\n    url\n    proto\n    headers {\n      key\n      value\n    }\n    body\n    response {\n      id\n      proto\n      headers {\n        key\n        value\n      }\n      statusCode\n      statusReason\n      body\n    }\n  }\n}\n    `;\n\n/**\n * __useHttpRequestLogQuery__\n *\n * To run a query within a React component, call `useHttpRequestLogQuery` and pass it any options that fit your needs.\n * When your component renders, `useHttpRequestLogQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useHttpRequestLogQuery({\n *   variables: {\n *      id: // value for 'id'\n *   },\n * });\n */\nexport function useHttpRequestLogQuery(baseOptions: Apollo.QueryHookOptions<HttpRequestLogQuery, HttpRequestLogQueryVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useQuery<HttpRequestLogQuery, HttpRequestLogQueryVariables>(HttpRequestLogDocument, options);\n      }\nexport function useHttpRequestLogLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<HttpRequestLogQuery, HttpRequestLogQueryVariables>) {\n          const options = {...defaultOptions, ...baseOptions}\n          return Apollo.useLazyQuery<HttpRequestLogQuery, HttpRequestLogQueryVariables>(HttpRequestLogDocument, options);\n        }\nexport type HttpRequestLogQueryHookResult = ReturnType<typeof useHttpRequestLogQuery>;\nexport type HttpRequestLogLazyQueryHookResult = ReturnType<typeof useHttpRequestLogLazyQuery>;\nexport type HttpRequestLogQueryResult = Apollo.QueryResult<HttpRequestLogQuery, HttpRequestLogQueryVariables>;\nexport const HttpRequestLogFilterDocument = gql`\n    query HttpRequestLogFilter {\n  httpRequestLogFilter {\n    onlyInScope\n    searchExpression\n  }\n}\n    `;\n\n/**\n * __useHttpRequestLogFilterQuery__\n *\n * To run a query within a React component, call `useHttpRequestLogFilterQuery` and pass it any options that fit your needs.\n * When your component renders, `useHttpRequestLogFilterQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useHttpRequestLogFilterQuery({\n *   variables: {\n *   },\n * });\n */\nexport function useHttpRequestLogFilterQuery(baseOptions?: Apollo.QueryHookOptions<HttpRequestLogFilterQuery, HttpRequestLogFilterQueryVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useQuery<HttpRequestLogFilterQuery, HttpRequestLogFilterQueryVariables>(HttpRequestLogFilterDocument, options);\n      }\nexport function useHttpRequestLogFilterLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<HttpRequestLogFilterQuery, HttpRequestLogFilterQueryVariables>) {\n          const options = {...defaultOptions, ...baseOptions}\n          return Apollo.useLazyQuery<HttpRequestLogFilterQuery, HttpRequestLogFilterQueryVariables>(HttpRequestLogFilterDocument, options);\n        }\nexport type HttpRequestLogFilterQueryHookResult = ReturnType<typeof useHttpRequestLogFilterQuery>;\nexport type HttpRequestLogFilterLazyQueryHookResult = ReturnType<typeof useHttpRequestLogFilterLazyQuery>;\nexport type HttpRequestLogFilterQueryResult = Apollo.QueryResult<HttpRequestLogFilterQuery, HttpRequestLogFilterQueryVariables>;\nexport const HttpRequestLogsDocument = gql`\n    query HttpRequestLogs {\n  httpRequestLogs {\n    id\n    method\n    url\n    timestamp\n    response {\n      statusCode\n      statusReason\n    }\n  }\n}\n    `;\n\n/**\n * __useHttpRequestLogsQuery__\n *\n * To run a query within a React component, call `useHttpRequestLogsQuery` and pass it any options that fit your needs.\n * When your component renders, `useHttpRequestLogsQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useHttpRequestLogsQuery({\n *   variables: {\n *   },\n * });\n */\nexport function useHttpRequestLogsQuery(baseOptions?: Apollo.QueryHookOptions<HttpRequestLogsQuery, HttpRequestLogsQueryVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useQuery<HttpRequestLogsQuery, HttpRequestLogsQueryVariables>(HttpRequestLogsDocument, options);\n      }\nexport function useHttpRequestLogsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<HttpRequestLogsQuery, HttpRequestLogsQueryVariables>) {\n          const options = {...defaultOptions, ...baseOptions}\n          return Apollo.useLazyQuery<HttpRequestLogsQuery, HttpRequestLogsQueryVariables>(HttpRequestLogsDocument, options);\n        }\nexport type HttpRequestLogsQueryHookResult = ReturnType<typeof useHttpRequestLogsQuery>;\nexport type HttpRequestLogsLazyQueryHookResult = ReturnType<typeof useHttpRequestLogsLazyQuery>;\nexport type HttpRequestLogsQueryResult = Apollo.QueryResult<HttpRequestLogsQuery, HttpRequestLogsQueryVariables>;\nexport const SetHttpRequestLogFilterDocument = gql`\n    mutation SetHttpRequestLogFilter($filter: HttpRequestLogFilterInput) {\n  setHttpRequestLogFilter(filter: $filter) {\n    onlyInScope\n    searchExpression\n  }\n}\n    `;\nexport type SetHttpRequestLogFilterMutationFn = Apollo.MutationFunction<SetHttpRequestLogFilterMutation, SetHttpRequestLogFilterMutationVariables>;\n\n/**\n * __useSetHttpRequestLogFilterMutation__\n *\n * To run a mutation, you first call `useSetHttpRequestLogFilterMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useSetHttpRequestLogFilterMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [setHttpRequestLogFilterMutation, { data, loading, error }] = useSetHttpRequestLogFilterMutation({\n *   variables: {\n *      filter: // value for 'filter'\n *   },\n * });\n */\nexport function useSetHttpRequestLogFilterMutation(baseOptions?: Apollo.MutationHookOptions<SetHttpRequestLogFilterMutation, SetHttpRequestLogFilterMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<SetHttpRequestLogFilterMutation, SetHttpRequestLogFilterMutationVariables>(SetHttpRequestLogFilterDocument, options);\n      }\nexport type SetHttpRequestLogFilterMutationHookResult = ReturnType<typeof useSetHttpRequestLogFilterMutation>;\nexport type SetHttpRequestLogFilterMutationResult = Apollo.MutationResult<SetHttpRequestLogFilterMutation>;\nexport type SetHttpRequestLogFilterMutationOptions = Apollo.BaseMutationOptions<SetHttpRequestLogFilterMutation, SetHttpRequestLogFilterMutationVariables>;\nexport const ScopeDocument = gql`\n    query Scope {\n  scope {\n    url\n  }\n}\n    `;\n\n/**\n * __useScopeQuery__\n *\n * To run a query within a React component, call `useScopeQuery` and pass it any options that fit your needs.\n * When your component renders, `useScopeQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useScopeQuery({\n *   variables: {\n *   },\n * });\n */\nexport function useScopeQuery(baseOptions?: Apollo.QueryHookOptions<ScopeQuery, ScopeQueryVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useQuery<ScopeQuery, ScopeQueryVariables>(ScopeDocument, options);\n      }\nexport function useScopeLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ScopeQuery, ScopeQueryVariables>) {\n          const options = {...defaultOptions, ...baseOptions}\n          return Apollo.useLazyQuery<ScopeQuery, ScopeQueryVariables>(ScopeDocument, options);\n        }\nexport type ScopeQueryHookResult = ReturnType<typeof useScopeQuery>;\nexport type ScopeLazyQueryHookResult = ReturnType<typeof useScopeLazyQuery>;\nexport type ScopeQueryResult = Apollo.QueryResult<ScopeQuery, ScopeQueryVariables>;\nexport const SetScopeDocument = gql`\n    mutation SetScope($scope: [ScopeRuleInput!]!) {\n  setScope(scope: $scope) {\n    url\n  }\n}\n    `;\nexport type SetScopeMutationFn = Apollo.MutationFunction<SetScopeMutation, SetScopeMutationVariables>;\n\n/**\n * __useSetScopeMutation__\n *\n * To run a mutation, you first call `useSetScopeMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useSetScopeMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [setScopeMutation, { data, loading, error }] = useSetScopeMutation({\n *   variables: {\n *      scope: // value for 'scope'\n *   },\n * });\n */\nexport function useSetScopeMutation(baseOptions?: Apollo.MutationHookOptions<SetScopeMutation, SetScopeMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<SetScopeMutation, SetScopeMutationVariables>(SetScopeDocument, options);\n      }\nexport type SetScopeMutationHookResult = ReturnType<typeof useSetScopeMutation>;\nexport type SetScopeMutationResult = Apollo.MutationResult<SetScopeMutation>;\nexport type SetScopeMutationOptions = Apollo.BaseMutationOptions<SetScopeMutation, SetScopeMutationVariables>;\nexport const CreateOrUpdateSenderRequestDocument = gql`\n    mutation CreateOrUpdateSenderRequest($request: SenderRequestInput!) {\n  createOrUpdateSenderRequest(request: $request) {\n    id\n  }\n}\n    `;\nexport type CreateOrUpdateSenderRequestMutationFn = Apollo.MutationFunction<CreateOrUpdateSenderRequestMutation, CreateOrUpdateSenderRequestMutationVariables>;\n\n/**\n * __useCreateOrUpdateSenderRequestMutation__\n *\n * To run a mutation, you first call `useCreateOrUpdateSenderRequestMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useCreateOrUpdateSenderRequestMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [createOrUpdateSenderRequestMutation, { data, loading, error }] = useCreateOrUpdateSenderRequestMutation({\n *   variables: {\n *      request: // value for 'request'\n *   },\n * });\n */\nexport function useCreateOrUpdateSenderRequestMutation(baseOptions?: Apollo.MutationHookOptions<CreateOrUpdateSenderRequestMutation, CreateOrUpdateSenderRequestMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<CreateOrUpdateSenderRequestMutation, CreateOrUpdateSenderRequestMutationVariables>(CreateOrUpdateSenderRequestDocument, options);\n      }\nexport type CreateOrUpdateSenderRequestMutationHookResult = ReturnType<typeof useCreateOrUpdateSenderRequestMutation>;\nexport type CreateOrUpdateSenderRequestMutationResult = Apollo.MutationResult<CreateOrUpdateSenderRequestMutation>;\nexport type CreateOrUpdateSenderRequestMutationOptions = Apollo.BaseMutationOptions<CreateOrUpdateSenderRequestMutation, CreateOrUpdateSenderRequestMutationVariables>;\nexport const CreateSenderRequestFromHttpRequestLogDocument = gql`\n    mutation CreateSenderRequestFromHttpRequestLog($id: ID!) {\n  createSenderRequestFromHttpRequestLog(id: $id) {\n    id\n  }\n}\n    `;\nexport type CreateSenderRequestFromHttpRequestLogMutationFn = Apollo.MutationFunction<CreateSenderRequestFromHttpRequestLogMutation, CreateSenderRequestFromHttpRequestLogMutationVariables>;\n\n/**\n * __useCreateSenderRequestFromHttpRequestLogMutation__\n *\n * To run a mutation, you first call `useCreateSenderRequestFromHttpRequestLogMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useCreateSenderRequestFromHttpRequestLogMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [createSenderRequestFromHttpRequestLogMutation, { data, loading, error }] = useCreateSenderRequestFromHttpRequestLogMutation({\n *   variables: {\n *      id: // value for 'id'\n *   },\n * });\n */\nexport function useCreateSenderRequestFromHttpRequestLogMutation(baseOptions?: Apollo.MutationHookOptions<CreateSenderRequestFromHttpRequestLogMutation, CreateSenderRequestFromHttpRequestLogMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<CreateSenderRequestFromHttpRequestLogMutation, CreateSenderRequestFromHttpRequestLogMutationVariables>(CreateSenderRequestFromHttpRequestLogDocument, options);\n      }\nexport type CreateSenderRequestFromHttpRequestLogMutationHookResult = ReturnType<typeof useCreateSenderRequestFromHttpRequestLogMutation>;\nexport type CreateSenderRequestFromHttpRequestLogMutationResult = Apollo.MutationResult<CreateSenderRequestFromHttpRequestLogMutation>;\nexport type CreateSenderRequestFromHttpRequestLogMutationOptions = Apollo.BaseMutationOptions<CreateSenderRequestFromHttpRequestLogMutation, CreateSenderRequestFromHttpRequestLogMutationVariables>;\nexport const SendRequestDocument = gql`\n    mutation SendRequest($id: ID!) {\n  sendRequest(id: $id) {\n    id\n  }\n}\n    `;\nexport type SendRequestMutationFn = Apollo.MutationFunction<SendRequestMutation, SendRequestMutationVariables>;\n\n/**\n * __useSendRequestMutation__\n *\n * To run a mutation, you first call `useSendRequestMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useSendRequestMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [sendRequestMutation, { data, loading, error }] = useSendRequestMutation({\n *   variables: {\n *      id: // value for 'id'\n *   },\n * });\n */\nexport function useSendRequestMutation(baseOptions?: Apollo.MutationHookOptions<SendRequestMutation, SendRequestMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<SendRequestMutation, SendRequestMutationVariables>(SendRequestDocument, options);\n      }\nexport type SendRequestMutationHookResult = ReturnType<typeof useSendRequestMutation>;\nexport type SendRequestMutationResult = Apollo.MutationResult<SendRequestMutation>;\nexport type SendRequestMutationOptions = Apollo.BaseMutationOptions<SendRequestMutation, SendRequestMutationVariables>;\nexport const GetSenderRequestDocument = gql`\n    query GetSenderRequest($id: ID!) {\n  senderRequest(id: $id) {\n    id\n    sourceRequestLogID\n    url\n    method\n    proto\n    headers {\n      key\n      value\n    }\n    body\n    timestamp\n    response {\n      id\n      proto\n      statusCode\n      statusReason\n      body\n      headers {\n        key\n        value\n      }\n    }\n  }\n}\n    `;\n\n/**\n * __useGetSenderRequestQuery__\n *\n * To run a query within a React component, call `useGetSenderRequestQuery` and pass it any options that fit your needs.\n * When your component renders, `useGetSenderRequestQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useGetSenderRequestQuery({\n *   variables: {\n *      id: // value for 'id'\n *   },\n * });\n */\nexport function useGetSenderRequestQuery(baseOptions: Apollo.QueryHookOptions<GetSenderRequestQuery, GetSenderRequestQueryVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useQuery<GetSenderRequestQuery, GetSenderRequestQueryVariables>(GetSenderRequestDocument, options);\n      }\nexport function useGetSenderRequestLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetSenderRequestQuery, GetSenderRequestQueryVariables>) {\n          const options = {...defaultOptions, ...baseOptions}\n          return Apollo.useLazyQuery<GetSenderRequestQuery, GetSenderRequestQueryVariables>(GetSenderRequestDocument, options);\n        }\nexport type GetSenderRequestQueryHookResult = ReturnType<typeof useGetSenderRequestQuery>;\nexport type GetSenderRequestLazyQueryHookResult = ReturnType<typeof useGetSenderRequestLazyQuery>;\nexport type GetSenderRequestQueryResult = Apollo.QueryResult<GetSenderRequestQuery, GetSenderRequestQueryVariables>;\nexport const GetSenderRequestsDocument = gql`\n    query GetSenderRequests {\n  senderRequests {\n    id\n    url\n    method\n    response {\n      id\n      statusCode\n      statusReason\n    }\n  }\n}\n    `;\n\n/**\n * __useGetSenderRequestsQuery__\n *\n * To run a query within a React component, call `useGetSenderRequestsQuery` and pass it any options that fit your needs.\n * When your component renders, `useGetSenderRequestsQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useGetSenderRequestsQuery({\n *   variables: {\n *   },\n * });\n */\nexport function useGetSenderRequestsQuery(baseOptions?: Apollo.QueryHookOptions<GetSenderRequestsQuery, GetSenderRequestsQueryVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useQuery<GetSenderRequestsQuery, GetSenderRequestsQueryVariables>(GetSenderRequestsDocument, options);\n      }\nexport function useGetSenderRequestsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetSenderRequestsQuery, GetSenderRequestsQueryVariables>) {\n          const options = {...defaultOptions, ...baseOptions}\n          return Apollo.useLazyQuery<GetSenderRequestsQuery, GetSenderRequestsQueryVariables>(GetSenderRequestsDocument, options);\n        }\nexport type GetSenderRequestsQueryHookResult = ReturnType<typeof useGetSenderRequestsQuery>;\nexport type GetSenderRequestsLazyQueryHookResult = ReturnType<typeof useGetSenderRequestsLazyQuery>;\nexport type GetSenderRequestsQueryResult = Apollo.QueryResult<GetSenderRequestsQuery, GetSenderRequestsQueryVariables>;\nexport const UpdateInterceptSettingsDocument = gql`\n    mutation UpdateInterceptSettings($input: UpdateInterceptSettingsInput!) {\n  updateInterceptSettings(input: $input) {\n    requestsEnabled\n    responsesEnabled\n    requestFilter\n    responseFilter\n  }\n}\n    `;\nexport type UpdateInterceptSettingsMutationFn = Apollo.MutationFunction<UpdateInterceptSettingsMutation, UpdateInterceptSettingsMutationVariables>;\n\n/**\n * __useUpdateInterceptSettingsMutation__\n *\n * To run a mutation, you first call `useUpdateInterceptSettingsMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useUpdateInterceptSettingsMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [updateInterceptSettingsMutation, { data, loading, error }] = useUpdateInterceptSettingsMutation({\n *   variables: {\n *      input: // value for 'input'\n *   },\n * });\n */\nexport function useUpdateInterceptSettingsMutation(baseOptions?: Apollo.MutationHookOptions<UpdateInterceptSettingsMutation, UpdateInterceptSettingsMutationVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useMutation<UpdateInterceptSettingsMutation, UpdateInterceptSettingsMutationVariables>(UpdateInterceptSettingsDocument, options);\n      }\nexport type UpdateInterceptSettingsMutationHookResult = ReturnType<typeof useUpdateInterceptSettingsMutation>;\nexport type UpdateInterceptSettingsMutationResult = Apollo.MutationResult<UpdateInterceptSettingsMutation>;\nexport type UpdateInterceptSettingsMutationOptions = Apollo.BaseMutationOptions<UpdateInterceptSettingsMutation, UpdateInterceptSettingsMutationVariables>;\nexport const GetInterceptedRequestsDocument = gql`\n    query GetInterceptedRequests {\n  interceptedRequests {\n    id\n    url\n    method\n    response {\n      statusCode\n      statusReason\n    }\n  }\n}\n    `;\n\n/**\n * __useGetInterceptedRequestsQuery__\n *\n * To run a query within a React component, call `useGetInterceptedRequestsQuery` and pass it any options that fit your needs.\n * When your component renders, `useGetInterceptedRequestsQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useGetInterceptedRequestsQuery({\n *   variables: {\n *   },\n * });\n */\nexport function useGetInterceptedRequestsQuery(baseOptions?: Apollo.QueryHookOptions<GetInterceptedRequestsQuery, GetInterceptedRequestsQueryVariables>) {\n        const options = {...defaultOptions, ...baseOptions}\n        return Apollo.useQuery<GetInterceptedRequestsQuery, GetInterceptedRequestsQueryVariables>(GetInterceptedRequestsDocument, options);\n      }\nexport function useGetInterceptedRequestsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetInterceptedRequestsQuery, GetInterceptedRequestsQueryVariables>) {\n          const options = {...defaultOptions, ...baseOptions}\n          return Apollo.useLazyQuery<GetInterceptedRequestsQuery, GetInterceptedRequestsQueryVariables>(GetInterceptedRequestsDocument, options);\n        }\nexport type GetInterceptedRequestsQueryHookResult = ReturnType<typeof useGetInterceptedRequestsQuery>;\nexport type GetInterceptedRequestsLazyQueryHookResult = ReturnType<typeof useGetInterceptedRequestsLazyQuery>;\nexport type GetInterceptedRequestsQueryResult = Apollo.QueryResult<GetInterceptedRequestsQuery, GetInterceptedRequestsQueryVariables>;"
  },
  {
    "path": "admin/src/lib/graphql/interceptedRequests.graphql",
    "content": "query GetInterceptedRequests {\n  interceptedRequests {\n    id\n    url\n    method\n    response {\n      statusCode\n      statusReason\n    }\n  }\n}\n"
  },
  {
    "path": "admin/src/lib/graphql/omitTypename.ts",
    "content": "function omitTypename<T>(key: string, value: T): T | undefined {\n  return key === \"__typename\" ? undefined : value;\n}\n\nexport function withoutTypename<T>(input: T): T {\n  return JSON.parse(JSON.stringify(input), omitTypename);\n}\n"
  },
  {
    "path": "admin/src/lib/graphql/useApollo.ts",
    "content": "import { ApolloClient, HttpLink, InMemoryCache, NormalizedCacheObject } from \"@apollo/client\";\n\nlet apolloClient: ApolloClient<NormalizedCacheObject>;\n\nfunction createApolloClient() {\n  return new ApolloClient({\n    ssrMode: typeof window === \"undefined\",\n    link: new HttpLink({\n      uri: \"/api/graphql/\",\n    }),\n    cache: new InMemoryCache({\n      typePolicies: {\n        Query: {\n          fields: {\n            interceptedRequests: {\n              merge(_, incoming) {\n                return incoming;\n              },\n            },\n          },\n        },\n        ProjectSettings: {\n          merge: true,\n        },\n      },\n    }),\n  });\n}\n\nexport function useApollo() {\n  const _apolloClient = apolloClient ?? createApolloClient();\n\n  // For SSG and SSR always create a new Apollo Client\n  if (typeof window === \"undefined\") return _apolloClient;\n  // Create the Apollo Client once in the client\n  if (!apolloClient) apolloClient = _apolloClient;\n\n  return _apolloClient;\n}\n"
  },
  {
    "path": "admin/src/lib/mui/createEmotionCache.ts",
    "content": "import createCache from \"@emotion/cache\";\n\n// prepend: true moves MUI styles to the top of the <head> so they're loaded first.\n// It allows developers to easily override MUI styles with other styling solutions, like CSS modules.\nexport default function createEmotionCache() {\n  return createCache({ key: \"css\", prepend: true });\n}\n"
  },
  {
    "path": "admin/src/lib/mui/theme.ts",
    "content": "import * as colors from \"@mui/material/colors\";\nimport { createTheme } from \"@mui/material/styles\";\n\ndeclare module \"@mui/material/Paper\" {\n  interface PaperPropsVariantOverrides {\n    centered: true;\n  }\n}\n\nconst heading = {\n  fontFamily: \"'JetBrains Mono', monospace\",\n  fontWeight: 600,\n};\n\nlet theme = createTheme({\n  palette: {\n    mode: \"dark\",\n    primary: {\n      main: colors.teal[\"A400\"],\n    },\n    secondary: {\n      main: colors.grey[900],\n      light: \"#333\",\n      dark: colors.common.black,\n    },\n  },\n  typography: {\n    h2: heading,\n    h3: heading,\n    h4: heading,\n    h5: heading,\n    h6: heading,\n  },\n});\n\ntheme = createTheme(theme, {\n  palette: {\n    background: {\n      default: theme.palette.secondary.main,\n      paper: theme.palette.secondary.light,\n    },\n    info: {\n      main: theme.palette.primary.main,\n    },\n    success: {\n      main: theme.palette.primary.main,\n    },\n  },\n  components: {\n    MuiTableRow: {\n      styleOverrides: {\n        root: {\n          \"&.Mui-selected, &.Mui-selected:hover\": {\n            backgroundColor: theme.palette.grey[700],\n          },\n        },\n      },\n    },\n    MuiPaper: {\n      variants: [\n        {\n          props: { variant: \"centered\" },\n          style: {\n            display: \"flex\",\n            justifyContent: \"center\",\n            alignItems: \"center\",\n            padding: theme.spacing(4),\n          },\n        },\n      ],\n    },\n  },\n});\n\nexport default theme;\n"
  },
  {
    "path": "admin/src/lib/queryParamsFromURL.tsx",
    "content": "import { KeyValuePair } from \"./components/KeyValuePair\";\n\nexport function queryParamsFromURL(url: string): KeyValuePair[] {\n  const questionMarkIndex = url.indexOf(\"?\");\n  if (questionMarkIndex === -1) {\n    return [];\n  }\n\n  const queryParams: KeyValuePair[] = [];\n\n  const searchParams = new URLSearchParams(url.slice(questionMarkIndex + 1));\n  for (const [key, value] of searchParams) {\n    queryParams.push({ key, value });\n  }\n\n  return queryParams;\n}\n"
  },
  {
    "path": "admin/src/lib/updateKeyPairItem.ts",
    "content": "import { KeyValuePair } from \"./components/KeyValuePair\";\n\nfunction updateKeyPairItem(key: string, value: string, idx: number, items: KeyValuePair[]): KeyValuePair[] {\n  const updated = [...items];\n  updated[idx] = { key, value };\n\n  // Append an empty key-value pair if the last item in the array isn't blank\n  // anymore.\n  if (items.length - 1 === idx && items[idx].key === \"\" && items[idx].value === \"\") {\n    updated.push({ key: \"\", value: \"\" });\n  }\n\n  return updated;\n}\n\nexport default updateKeyPairItem;\n"
  },
  {
    "path": "admin/src/lib/updateURLQueryParams.ts",
    "content": "import { KeyValuePair } from \"./components/KeyValuePair\";\n\nfunction updateURLQueryParams(url: string, queryParams: KeyValuePair[]) {\n  // Note: We don't use the `URL` interface, because we're potentially dealing\n  // with malformed/incorrect URLs, which would yield TypeErrors when constructed\n  // via `URL`.\n  let newURL = url;\n\n  const questionMarkIndex = url.indexOf(\"?\");\n  if (questionMarkIndex !== -1) {\n    newURL = newURL.slice(0, questionMarkIndex);\n  }\n\n  const searchParams = new URLSearchParams();\n  for (const { key, value } of queryParams.filter(({ key }) => key !== \"\")) {\n    searchParams.append(key, value);\n  }\n\n  const rawQueryParams = decodeURI(searchParams.toString());\n\n  if (rawQueryParams == \"\") {\n    return newURL;\n  }\n\n  return newURL + \"?\" + rawQueryParams;\n}\n\nexport default updateURLQueryParams;\n"
  },
  {
    "path": "admin/src/pages/_app.tsx",
    "content": "import { ApolloProvider } from \"@apollo/client\";\nimport { CacheProvider, EmotionCache } from \"@emotion/react\";\nimport { ThemeProvider } from \"@mui/material\";\nimport CssBaseline from \"@mui/material/CssBaseline\";\nimport { AppProps } from \"next/app\";\nimport Head from \"next/head\";\nimport React from \"react\";\n\nimport { ActiveProjectProvider } from \"lib/ActiveProjectContext\";\nimport { InterceptedRequestsProvider } from \"lib/InterceptedRequestsContext\";\nimport { useApollo } from \"lib/graphql/useApollo\";\nimport createEmotionCache from \"lib/mui/createEmotionCache\";\nimport theme from \"lib/mui/theme\";\n\nimport \"../styles.css\";\n\n// Client-side cache, shared for the whole session of the user in the browser.\nconst clientSideEmotionCache = createEmotionCache();\n\ninterface MyAppProps extends AppProps {\n  emotionCache?: EmotionCache;\n}\n\nexport default function MyApp(props: MyAppProps) {\n  const { Component, emotionCache = clientSideEmotionCache, pageProps } = props;\n  const apolloClient = useApollo();\n\n  return (\n    <CacheProvider value={emotionCache}>\n      <Head>\n        <title>Hetty://</title>\n        <meta name=\"viewport\" content=\"initial-scale=1, width=device-width\" />\n      </Head>\n      <ApolloProvider client={apolloClient}>\n        <ActiveProjectProvider>\n          <InterceptedRequestsProvider>\n            <ThemeProvider theme={theme}>\n              <CssBaseline />\n              <Component {...pageProps} />\n            </ThemeProvider>\n          </InterceptedRequestsProvider>\n        </ActiveProjectProvider>\n      </ApolloProvider>\n    </CacheProvider>\n  );\n}\n"
  },
  {
    "path": "admin/src/pages/_document.tsx",
    "content": "import createEmotionServer from \"@emotion/server/create-instance\";\nimport Document, { Html, Head, Main, NextScript } from \"next/document\";\nimport React from \"react\";\n\nimport createEmotionCache from \"lib/mui/createEmotionCache\";\nimport theme from \"lib/mui/theme\";\n\nexport default class MyDocument extends Document {\n  /* eslint-disable */\n  render() {\n    return (\n      <Html lang=\"en\">\n        <Head>\n          <meta name=\"theme-color\" content={theme.palette.primary.main} />\n          <link rel=\"stylesheet\" href=\"/style.css\" />\n          <link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap\" />\n          <link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap\" />\n          {(this.props as any).emotionStyleTags}\n        </Head>\n        <body>\n          <Main />\n          <NextScript />\n        </body>\n      </Html>\n    );\n  }\n}\n\n// `getInitialProps` belongs to `_document` (instead of `_app`),\n// it's compatible with static-site generation (SSG).\nMyDocument.getInitialProps = async (ctx) => {\n  // Resolution order\n  //\n  // On the server:\n  // 1. app.getInitialProps\n  // 2. page.getInitialProps\n  // 3. document.getInitialProps\n  // 4. app.render\n  // 5. page.render\n  // 6. document.render\n  //\n  // On the server with error:\n  // 1. document.getInitialProps\n  // 2. app.render\n  // 3. page.render\n  // 4. document.render\n  //\n  // On the client\n  // 1. app.getInitialProps\n  // 2. page.getInitialProps\n  // 3. app.render\n  // 4. page.render\n\n  const originalRenderPage = ctx.renderPage;\n\n  // You can consider sharing the same emotion cache between all the SSR requests to speed up performance.\n  // However, be aware that it can have global side effects.\n  const cache = createEmotionCache();\n  const { extractCriticalToChunks } = createEmotionServer(cache);\n\n  ctx.renderPage = () =>\n    originalRenderPage({\n      enhanceApp: (App: any) =>\n        function EnhanceApp(props) {\n          return <App emotionCache={cache} {...props} />;\n        },\n    });\n\n  const initialProps = await Document.getInitialProps(ctx);\n  // This is important. It prevents emotion to render invalid HTML.\n  // See https://github.com/mui-org/material-ui/issues/26561#issuecomment-855286153\n  const emotionStyles = extractCriticalToChunks(initialProps.html);\n  const emotionStyleTags = emotionStyles.styles.map((style) => (\n    <style\n      data-emotion={`${style.key} ${style.ids.join(\" \")}`}\n      key={style.key}\n      // eslint-disable-next-line react/no-danger\n      dangerouslySetInnerHTML={{ __html: style.css }}\n    />\n  ));\n\n  return {\n    ...initialProps,\n    emotionStyleTags,\n  };\n};\n"
  },
  {
    "path": "admin/src/pages/index.tsx",
    "content": "import FolderIcon from \"@mui/icons-material/Folder\";\nimport { Box, Button, Typography } from \"@mui/material\";\nimport Link from \"next/link\";\n\nimport { Layout, Page } from \"features/Layout\";\n\nfunction Index(): JSX.Element {\n  const highlightSx = { color: \"primary.main\" };\n\n  return (\n    <Layout page={Page.Home} title=\"\">\n      <Box p={4}>\n        <Box mb={4} width=\"60%\">\n          <Typography variant=\"h2\">\n            <Box component=\"span\" sx={highlightSx}>\n              Hetty://\n            </Box>\n            <br />\n            The simple HTTP toolkit for security research.\n          </Typography>\n        </Box>\n\n        <Typography\n          paragraph\n          sx={{\n            fontSize: \"1.6rem\",\n            width: \"60%\",\n            lineHeight: 2,\n            mb: 5,\n          }}\n        >\n          Welcome to{\" \"}\n          <Box component=\"span\" sx={highlightSx}>\n            Hetty\n          </Box>\n          . Get started by creating a project.\n        </Typography>\n\n        <Link href=\"/projects\" passHref>\n          <Button\n            sx={{ mr: 2 }}\n            variant=\"contained\"\n            color=\"primary\"\n            component=\"a\"\n            size=\"large\"\n            startIcon={<FolderIcon />}\n          >\n            Manage projects\n          </Button>\n        </Link>\n      </Box>\n    </Layout>\n  );\n}\n\nexport default Index;\n"
  },
  {
    "path": "admin/src/pages/projects/index.tsx",
    "content": "import { Box, Divider, Grid, Typography } from \"@mui/material\";\n\nimport { Layout, Page } from \"features/Layout\";\nimport NewProject from \"features/projects/components/NewProject\";\nimport ProjectList from \"features/projects/components/ProjectList\";\n\nfunction Index(): JSX.Element {\n  return (\n    <Layout page={Page.Projects} title=\"Projects\">\n      <Box p={4}>\n        <Box mb={3}>\n          <Typography variant=\"h4\">Projects</Typography>\n        </Box>\n        <Typography paragraph>\n          Projects contain settings and data generated/processed by Hetty. They are stored in a single database on disk.\n        </Typography>\n        <Box my={4}>\n          <Divider />\n        </Box>\n        <Box mb={8}>\n          <NewProject />\n        </Box>\n        <Grid container>\n          <Grid item xs={12} sm={8} md={6} lg={6}>\n            <ProjectList />\n          </Grid>\n        </Grid>\n      </Box>\n    </Layout>\n  );\n}\n\nexport default Index;\n"
  },
  {
    "path": "admin/src/pages/proxy/index.tsx",
    "content": "import ListIcon from \"@mui/icons-material/List\";\nimport { Button, Typography } from \"@mui/material\";\nimport Link from \"next/link\";\nimport React from \"react\";\n\nimport { Layout, Page } from \"features/Layout\";\n\nfunction Index(): JSX.Element {\n  return (\n    <Layout page={Page.ProxySetup} title=\"Proxy setup\">\n      <Typography paragraph>Coming soon…</Typography>\n      <Link href=\"/proxy/logs\" passHref>\n        <Button variant=\"contained\" color=\"primary\" component=\"a\" size=\"large\" startIcon={<ListIcon />}>\n          View logs\n        </Button>\n      </Link>\n    </Layout>\n  );\n}\n\nexport default Index;\n"
  },
  {
    "path": "admin/src/pages/proxy/intercept/index.tsx",
    "content": "import { Layout, Page } from \"features/Layout\";\nimport Intercept from \"features/intercept/components/Intercept\";\n\nfunction ProxyIntercept(): JSX.Element {\n  return (\n    <Layout page={Page.Intercept} title=\"Proxy intercept\">\n      <Intercept />\n    </Layout>\n  );\n}\n\nexport default ProxyIntercept;\n"
  },
  {
    "path": "admin/src/pages/proxy/logs/index.tsx",
    "content": "import { Layout, Page } from \"features/Layout\";\nimport RequestLogs from \"features/reqlog\";\n\nfunction ProxyLogs(): JSX.Element {\n  return (\n    <Layout page={Page.ProxyLogs} title=\"Proxy logs\">\n      <RequestLogs />\n    </Layout>\n  );\n}\n\nexport default ProxyLogs;\n"
  },
  {
    "path": "admin/src/pages/scope/index.tsx",
    "content": "import { Box, Divider, Grid, Typography } from \"@mui/material\";\nimport React from \"react\";\n\nimport { Layout, Page } from \"features/Layout\";\nimport AddRule from \"features/scope/components/AddRule\";\nimport Rules from \"features/scope/components/Rules\";\n\nfunction Index(): JSX.Element {\n  return (\n    <Layout page={Page.Scope} title=\"Scope\">\n      <Box p={4}>\n        <Box mb={3}>\n          <Typography variant=\"h4\">Scope</Typography>\n        </Box>\n        <Typography paragraph>\n          Scope rules are used by various modules in Hetty and can influence their behavior. For example: the Proxy logs\n          module can match incoming requests against scope rules and decide its behavior (e.g. log or bypass) based on\n          the outcome of the match. All scope configuration is stored per project.\n        </Typography>\n        <Box my={4}>\n          <Divider />\n        </Box>\n        <Grid container>\n          <Grid item xs={12} sm={12} md={8} lg={6}>\n            <AddRule />\n            <Box my={4}>\n              <Divider />\n            </Box>\n            <Rules />\n          </Grid>\n        </Grid>\n      </Box>\n    </Layout>\n  );\n}\n\nexport default Index;\n"
  },
  {
    "path": "admin/src/pages/sender/index.tsx",
    "content": "import { Layout, Page } from \"features/Layout\";\nimport Sender from \"features/sender\";\n\nfunction Index(): JSX.Element {\n  return (\n    <Layout page={Page.Sender} title=\"Sender\">\n      <Sender />\n    </Layout>\n  );\n}\n\nexport default Index;\n"
  },
  {
    "path": "admin/src/pages/settings/index.tsx",
    "content": "import { Layout, Page } from \"features/Layout\";\nimport Settings from \"features/settings/components/Settings\";\n\nfunction Index(): JSX.Element {\n  return (\n    <Layout page={Page.Settings} title=\"Settings\">\n      <Settings />\n    </Layout>\n  );\n}\n\nexport default Index;\n"
  },
  {
    "path": "admin/src/styles.css",
    "content": "html,\nbody,\n#__next {\n  height: 100%;\n}\n"
  },
  {
    "path": "admin/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"baseUrl\": \"src\",\n    \"paths\": {\n      \"src/*\": [\"./src/*\"]\n    },\n    \"downlevelIteration\": true,\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\",\n    \"incremental\": true\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "cmd/hetty/cert.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"fmt\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/peterbourgon/ff/v3/ffcli\"\n\t\"github.com/smallstep/truststore\"\n)\n\nvar certUsage = `\nUsage:\n    hetty cert <subcommand> [flags]\n\nCertificate management tools.\n\nOptions:\n    --help, -h  Output this usage text.\n\nSubcommands:\n    - install    Installs a certificate to the system trust store, and\n                 (optionally) to the Firefox and Java trust stores.\n    - uninstall  Uninstalls a certificate from the system trust store, and\n                 (optionally) from the Firefox and Java trust stores.\n\nRun ` + \"`hetty cert <subcommand> --help`\" + ` for subcommand specific usage instructions.\n\nVisit https://hetty.xyz to learn more about Hetty.\n`\n\nvar certInstallUsage = `\nUsage:\n    hetty cert install [flags]\n\t\nInstalls a certificate to the system trust store, and (optionally) to the Firefox\nand Java trust stores.\n\nOptions:\n    --cert         Path to certificate. (Default: \"~/.hetty/hetty_cert.pem\")\n    --firefox      Install certificate to Firefox trust store. (Default: false)\n    --java         Install certificate to Java trust store. (Default: false)\n    --skip-system  Skip installing certificate to system trust store (Default: false)\n    --help, -h     Output this usage text.\n\nVisit https://hetty.xyz to learn more about Hetty.\n`\n\nvar certUninstallUsage = `\nUsage:\n    hetty cert uninstall [flags]\n\t\nUninstalls a certificate from the system trust store, and (optionally) from the Firefox\nand Java trust stores.\n\nOptions:\n    --cert         Path to certificate. (Default: \"~/.hetty/hetty_cert.pem\")\n    --firefox      Uninstall certificate from Firefox trust store. (Default: false)\n    --java         Uninstall certificate from Java trust store. (Default: false)\n    --skip-system  Skip uninstalling certificate from system trust store (Default: false)\n    --help, -h     Output this usage text.\n\nVisit https://hetty.xyz to learn more about Hetty.\n`\n\ntype CertInstallCommand struct {\n\tconfig     *Config\n\tcert       string\n\tfirefox    bool\n\tjava       bool\n\tskipSystem bool\n}\n\ntype CertUninstallCommand struct {\n\tconfig     *Config\n\tcert       string\n\tfirefox    bool\n\tjava       bool\n\tskipSystem bool\n}\n\nfunc NewCertCommand(rootConfig *Config) *ffcli.Command {\n\treturn &ffcli.Command{\n\t\tName: \"cert\",\n\t\tSubcommands: []*ffcli.Command{\n\t\t\tNewCertInstallCommand(rootConfig),\n\t\t\tNewCertUninstallCommand(rootConfig),\n\t\t},\n\t\tExec: func(context.Context, []string) error {\n\t\t\treturn flag.ErrHelp\n\t\t},\n\t\tUsageFunc: func(*ffcli.Command) string {\n\t\t\treturn certUsage\n\t\t},\n\t}\n}\n\nfunc NewCertInstallCommand(rootConfig *Config) *ffcli.Command {\n\tcmd := CertInstallCommand{\n\t\tconfig: rootConfig,\n\t}\n\tfs := flag.NewFlagSet(\"hetty cert install\", flag.ExitOnError)\n\n\tfs.StringVar(&cmd.cert, \"cert\", \"~/.hetty/hetty_cert.pem\", \"Path to certificate.\")\n\tfs.BoolVar(&cmd.firefox, \"firefox\", false, \"Install certificate to Firefox trust store. (Default: false)\")\n\tfs.BoolVar(&cmd.java, \"java\", false, \"Install certificate to Java trust store. (Default: false)\")\n\tfs.BoolVar(&cmd.skipSystem, \"skip-system\", false, \"Skip installing certificate to system trust store (Default: false)\")\n\n\tcmd.config.RegisterFlags(fs)\n\n\treturn &ffcli.Command{\n\t\tName:    \"install\",\n\t\tFlagSet: fs,\n\t\tExec:    cmd.Exec,\n\t\tUsageFunc: func(*ffcli.Command) string {\n\t\t\treturn certInstallUsage\n\t\t},\n\t}\n}\n\nfunc (cmd *CertInstallCommand) Exec(_ context.Context, _ []string) error {\n\tcaCertFile, err := homedir.Expand(cmd.cert)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse certificate filepath: %w\", err)\n\t}\n\n\topts := []truststore.Option{}\n\n\tif cmd.skipSystem {\n\t\topts = append(opts, truststore.WithNoSystem())\n\t}\n\n\tif cmd.firefox {\n\t\topts = append(opts, truststore.WithFirefox())\n\t}\n\n\tif cmd.java {\n\t\topts = append(opts, truststore.WithJava())\n\t}\n\n\tif !cmd.skipSystem {\n\t\tcmd.config.logger.Info(\n\t\t\t\"To install the certificate in the system trust store, you might be prompted for your password.\")\n\t}\n\n\tif err := truststore.InstallFile(caCertFile, opts...); err != nil {\n\t\treturn fmt.Errorf(\"failed to install certificate: %w\", err)\n\t}\n\n\tcmd.config.logger.Info(\"Finished installing certificate.\")\n\n\treturn nil\n}\n\nfunc NewCertUninstallCommand(rootConfig *Config) *ffcli.Command {\n\tcmd := CertUninstallCommand{\n\t\tconfig: rootConfig,\n\t}\n\tfs := flag.NewFlagSet(\"hetty cert uninstall\", flag.ExitOnError)\n\n\tfs.StringVar(&cmd.cert, \"cert\", \"~/.hetty/hetty_cert.pem\", \"Path to certificate.\")\n\tfs.BoolVar(&cmd.firefox, \"firefox\", false, \"Uninstall certificate from Firefox trust store. (Default: false)\")\n\tfs.BoolVar(&cmd.java, \"java\", false, \"Uninstall certificate from Java trust store. (Default: false)\")\n\tfs.BoolVar(&cmd.skipSystem, \"skip-system\", false,\n\t\t\"Skip uninstalling certificate from system trust store (Default: false)\")\n\n\tcmd.config.RegisterFlags(fs)\n\n\treturn &ffcli.Command{\n\t\tName:    \"uninstall\",\n\t\tFlagSet: fs,\n\t\tExec:    cmd.Exec,\n\t\tUsageFunc: func(*ffcli.Command) string {\n\t\t\treturn certUninstallUsage\n\t\t},\n\t}\n}\n\nfunc (cmd *CertUninstallCommand) Exec(_ context.Context, _ []string) error {\n\tcaCertFile, err := homedir.Expand(cmd.cert)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse certificate filepath: %w\", err)\n\t}\n\n\topts := []truststore.Option{}\n\n\tif cmd.skipSystem {\n\t\topts = append(opts, truststore.WithNoSystem())\n\t}\n\n\tif cmd.firefox {\n\t\topts = append(opts, truststore.WithFirefox())\n\t}\n\n\tif cmd.java {\n\t\topts = append(opts, truststore.WithJava())\n\t}\n\n\tif !cmd.skipSystem {\n\t\tcmd.config.logger.Info(\n\t\t\t\"To uninstall the certificate from the system trust store, you might be prompted for your password.\")\n\t}\n\n\tif err := truststore.UninstallFile(caCertFile, opts...); err != nil {\n\t\treturn fmt.Errorf(\"failed to uninstall certificate: %w\", err)\n\t}\n\n\tcmd.config.logger.Info(\"Finished uninstalling certificate.\")\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/hetty/config.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\n\t\"go.uber.org/zap\"\n)\n\n// Config represents the global configuration shared amongst all commands.\ntype Config struct {\n\tverbose  bool\n\tjsonLogs bool\n\tlogger   *zap.Logger\n}\n\n// RegisterFlags registers the flag fields into the provided flag.FlagSet. This\n// helper function allows subcommands to register the root flags into their\n// flagsets, creating \"global\" flags that can be passed after any subcommand at\n// the commandline.\nfunc (cfg *Config) RegisterFlags(fs *flag.FlagSet) {\n\tfs.BoolVar(&cfg.verbose, \"verbose\", false, \"Enable verbose logging.\")\n\tfs.BoolVar(&cfg.jsonLogs, \"json\", false, \"Encode logs as JSON, instead of pretty/human readable output.\")\n}\n"
  },
  {
    "path": "cmd/hetty/hetty.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"embed\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"net\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"os/signal\"\n\t\"strings\"\n\n\t\"github.com/chromedp/chromedp\"\n\t\"github.com/gorilla/mux\"\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/peterbourgon/ff/v3/ffcli\"\n\t\"go.etcd.io/bbolt\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/dstotijn/hetty/pkg/api\"\n\t\"github.com/dstotijn/hetty/pkg/chrome\"\n\t\"github.com/dstotijn/hetty/pkg/db/bolt\"\n\t\"github.com/dstotijn/hetty/pkg/proj\"\n\t\"github.com/dstotijn/hetty/pkg/proxy\"\n\t\"github.com/dstotijn/hetty/pkg/proxy/intercept\"\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n\t\"github.com/dstotijn/hetty/pkg/sender\"\n)\n\nvar version = \"0.0.0\"\n\n//go:embed admin\n//go:embed admin/_next/static\n//go:embed admin/_next/static/chunks/pages/*.js\n//go:embed admin/_next/static/*/*.js\nvar adminContent embed.FS\n\nvar hettyUsage = `\nUsage:\n    hetty [flags] [subcommand] [flags]\n\nRuns an HTTP server with (MITM) proxy, GraphQL service, and a web based admin interface.\n\nOptions:\n    --cert         Path to root CA certificate. Creates file if it doesn't exist. (Default: \"~/.hetty/hetty_cert.pem\")\n    --key          Path to root CA private key. Creates file if it doesn't exist. (Default: \"~/.hetty/hetty_key.pem\")\n    --db           Database file path. Creates file if it doesn't exist. (Default: \"~/.hetty/hetty.db\")\n    --addr         TCP address for HTTP server to listen on, in the form \\\"host:port\\\". (Default: \":8080\")\n    --chrome       Launch Chrome with proxy settings applied and certificate errors ignored. (Default: false)\n    --verbose      Enable verbose logging.\n    --json         Encode logs as JSON, instead of pretty/human readable output.\n    --version, -v  Output version.\n    --help, -h     Output this usage text.\n\nSubcommands:\n    - cert  Certificate management\n\nRun ` + \"`hetty <subcommand> --help`\" + ` for subcommand specific usage instructions.\n\nVisit https://hetty.xyz to learn more about Hetty.\n`\n\ntype HettyCommand struct {\n\tconfig *Config\n\n\tcert    string\n\tkey     string\n\tdb      string\n\taddr    string\n\tchrome  bool\n\tversion bool\n}\n\nfunc NewHettyCommand() (*ffcli.Command, *Config) {\n\tcmd := HettyCommand{\n\t\tconfig: &Config{},\n\t}\n\n\tfs := flag.NewFlagSet(\"hetty\", flag.ExitOnError)\n\n\tfs.StringVar(&cmd.cert, \"cert\", \"~/.hetty/hetty_cert.pem\",\n\t\t\"Path to root CA certificate. Creates a new certificate if file doesn't exist.\")\n\tfs.StringVar(&cmd.key, \"key\", \"~/.hetty/hetty_key.pem\",\n\t\t\"Path to root CA private key. Creates a new private key if file doesn't exist.\")\n\tfs.StringVar(&cmd.db, \"db\", \"~/.hetty/hetty.db\", \"Database file path. Creates file if it doesn't exist.\")\n\tfs.StringVar(&cmd.addr, \"addr\", \":8080\", \"TCP address to listen on, in the form \\\"host:port\\\".\")\n\tfs.BoolVar(&cmd.chrome, \"chrome\", false, \"Launch Chrome with proxy settings applied and certificate errors ignored.\")\n\tfs.BoolVar(&cmd.version, \"version\", false, \"Output version.\")\n\tfs.BoolVar(&cmd.version, \"v\", false, \"Output version.\")\n\n\tcmd.config.RegisterFlags(fs)\n\n\treturn &ffcli.Command{\n\t\tName:    \"hetty\",\n\t\tFlagSet: fs,\n\t\tSubcommands: []*ffcli.Command{\n\t\t\tNewCertCommand(cmd.config),\n\t\t},\n\t\tExec: cmd.Exec,\n\t\tUsageFunc: func(*ffcli.Command) string {\n\t\t\treturn hettyUsage\n\t\t},\n\t}, cmd.config\n}\n\nfunc (cmd *HettyCommand) Exec(ctx context.Context, _ []string) error {\n\tctx, stop := signal.NotifyContext(ctx, os.Interrupt)\n\tdefer stop()\n\n\tif cmd.version {\n\t\tfmt.Fprint(os.Stdout, version+\"\\n\")\n\t\treturn nil\n\t}\n\n\tmainLogger := cmd.config.logger.Named(\"main\")\n\n\tlistenHost, listenPort, err := net.SplitHostPort(cmd.addr)\n\tif err != nil {\n\t\tmainLogger.Fatal(\"Failed to parse listening address.\", zap.Error(err))\n\t}\n\n\turl := fmt.Sprintf(\"http://%v:%v\", listenHost, listenPort)\n\tif listenHost == \"\" || listenHost == \"0.0.0.0\" || listenHost == \"127.0.0.1\" || listenHost == \"::1\" {\n\t\turl = fmt.Sprintf(\"http://localhost:%v\", listenPort)\n\t}\n\n\t// Expand `~` in filepaths.\n\tcaCertFile, err := homedir.Expand(cmd.cert)\n\tif err != nil {\n\t\tcmd.config.logger.Fatal(\"Failed to parse CA certificate filepath.\", zap.Error(err))\n\t}\n\n\tcaKeyFile, err := homedir.Expand(cmd.key)\n\tif err != nil {\n\t\tcmd.config.logger.Fatal(\"Failed to parse CA private key filepath.\", zap.Error(err))\n\t}\n\n\tdbPath, err := homedir.Expand(cmd.db)\n\tif err != nil {\n\t\tcmd.config.logger.Fatal(\"Failed to parse database path.\", zap.Error(err))\n\t}\n\n\t// Load existing CA certificate and key from disk, or generate and write\n\t// to disk if no files exist yet.\n\tcaCert, caKey, err := proxy.LoadOrCreateCA(caKeyFile, caCertFile)\n\tif err != nil {\n\t\tcmd.config.logger.Fatal(\"Failed to load or create CA key pair.\", zap.Error(err))\n\t}\n\n\tdbLogger := cmd.config.logger.Named(\"boltdb\").Sugar()\n\tboltOpts := *bbolt.DefaultOptions\n\tboltOpts.Logger = &bolt.Logger{SugaredLogger: dbLogger}\n\n\tboltDB, err := bolt.OpenDatabase(dbPath, &boltOpts)\n\tif err != nil {\n\t\tcmd.config.logger.Fatal(\"Failed to open database.\", zap.Error(err))\n\t}\n\tdefer boltDB.Close()\n\n\tscope := &scope.Scope{}\n\n\treqLogService := reqlog.NewService(reqlog.Config{\n\t\tScope:      scope,\n\t\tRepository: boltDB,\n\t\tLogger:     cmd.config.logger.Named(\"reqlog\").Sugar(),\n\t})\n\n\tinterceptService := intercept.NewService(intercept.Config{\n\t\tLogger: cmd.config.logger.Named(\"intercept\").Sugar(),\n\t})\n\n\tsenderService := sender.NewService(sender.Config{\n\t\tRepository:    boltDB,\n\t\tReqLogService: reqLogService,\n\t})\n\n\tprojService, err := proj.NewService(proj.Config{\n\t\tRepository:       boltDB,\n\t\tInterceptService: interceptService,\n\t\tReqLogService:    reqLogService,\n\t\tSenderService:    senderService,\n\t\tScope:            scope,\n\t})\n\tif err != nil {\n\t\tcmd.config.logger.Fatal(\"Failed to create new projects service.\", zap.Error(err))\n\t}\n\n\tproxy, err := proxy.NewProxy(proxy.Config{\n\t\tCACert: caCert,\n\t\tCAKey:  caKey,\n\t\tLogger: cmd.config.logger.Named(\"proxy\").Sugar(),\n\t})\n\tif err != nil {\n\t\tcmd.config.logger.Fatal(\"Failed to create new proxy.\", zap.Error(err))\n\t}\n\n\tproxy.UseRequestModifier(reqLogService.RequestModifier)\n\tproxy.UseResponseModifier(reqLogService.ResponseModifier)\n\tproxy.UseRequestModifier(interceptService.RequestModifier)\n\tproxy.UseResponseModifier(interceptService.ResponseModifier)\n\n\tfsSub, err := fs.Sub(adminContent, \"admin\")\n\tif err != nil {\n\t\tcmd.config.logger.Fatal(\"Failed to construct file system subtree from admin dir.\", zap.Error(err))\n\t}\n\n\tadminHandler := http.FileServer(http.FS(fsSub))\n\trouter := mux.NewRouter().SkipClean(true)\n\tadminRouter := router.MatcherFunc(func(req *http.Request, match *mux.RouteMatch) bool {\n\t\thostname, _ := os.Hostname()\n\t\thost, _, _ := net.SplitHostPort(req.Host)\n\n\t\t// Serve local admin routes when either:\n\t\t// - The `Host` is well-known, e.g. `hetty.proxy`, `localhost:[port]`\n\t\t//   or the listen addr `[host]:[port]`.\n\t\t// - The request is not for TLS proxying (e.g. no `CONNECT`) and not\n\t\t//   for proxying an external URL. E.g. Request-Line (RFC 7230, Section 3.1.1)\n\t\t//   has no scheme.\n\t\treturn strings.EqualFold(host, hostname) ||\n\t\t\treq.Host == \"hetty.proxy\" ||\n\t\t\treq.Host == fmt.Sprintf(\"%v:%v\", \"localhost\", listenPort) ||\n\t\t\treq.Host == fmt.Sprintf(\"%v:%v\", listenHost, listenPort) ||\n\t\t\treq.Method != http.MethodConnect && !strings.HasPrefix(req.RequestURI, \"http://\")\n\t}).Subrouter().StrictSlash(true)\n\n\t// GraphQL server.\n\tgqlEndpoint := \"/api/graphql/\"\n\tadminRouter.Path(gqlEndpoint).Handler(api.HTTPHandler(&api.Resolver{\n\t\tProjectService:    projService,\n\t\tRequestLogService: reqLogService,\n\t\tInterceptService:  interceptService,\n\t\tSenderService:     senderService,\n\t}, gqlEndpoint))\n\n\t// Admin interface.\n\tadminRouter.PathPrefix(\"\").Handler(adminHandler)\n\n\t// Fallback (default) is the Proxy handler.\n\trouter.PathPrefix(\"\").Handler(proxy)\n\n\thttpServer := &http.Server{\n\t\tAddr:         cmd.addr,\n\t\tHandler:      router,\n\t\tTLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){}, // Disable HTTP/2\n\t\tErrorLog:     zap.NewStdLog(cmd.config.logger.Named(\"http\")),\n\t}\n\n\tgo func() {\n\t\tmainLogger.Info(fmt.Sprintf(\"Hetty (v%v) is running on %v ...\", version, cmd.addr))\n\t\tmainLogger.Info(fmt.Sprintf(\"\\x1b[%dm%s\\x1b[0m\", uint8(32), \"Get started at \"+url))\n\n\t\terr := httpServer.ListenAndServe()\n\t\tif err != http.ErrServerClosed {\n\t\t\tmainLogger.Fatal(\"HTTP server closed unexpected.\", zap.Error(err))\n\t\t}\n\t}()\n\n\tif cmd.chrome {\n\t\tctx, cancel := chrome.NewExecAllocator(ctx, chrome.Config{\n\t\t\tProxyServer:      url,\n\t\t\tProxyBypassHosts: []string{url},\n\t\t})\n\t\tdefer cancel()\n\n\t\ttaskCtx, cancel := chromedp.NewContext(ctx)\n\t\tdefer cancel()\n\n\t\terr = chromedp.Run(taskCtx, chromedp.Navigate(url))\n\n\t\tswitch {\n\t\tcase errors.Is(err, exec.ErrNotFound):\n\t\t\tmainLogger.Info(\"Chrome executable not found.\")\n\t\tcase err != nil:\n\t\t\tmainLogger.Error(fmt.Sprintf(\"Failed to navigate to %v.\", url), zap.Error(err))\n\t\tdefault:\n\t\t\tmainLogger.Info(\"Launched Chrome.\")\n\t\t}\n\t}\n\n\t// Wait for interrupt signal.\n\t<-ctx.Done()\n\t// Restore signal, allowing \"force quit\".\n\tstop()\n\n\tmainLogger.Info(\"Shutting down HTTP server. Press Ctrl+C to force quit.\")\n\n\t// Note: We expect httpServer.Handler to handle timeouts, thus, we don't\n\t// need a context value with deadline here.\n\t//nolint:contextcheck\n\terr = httpServer.Shutdown(context.Background())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to shutdown HTTP server: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/hetty/main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"flag\"\n\tllog \"log\"\n\t\"os\"\n\n\t\"go.uber.org/zap\"\n\n\t\"github.com/dstotijn/hetty/pkg/log\"\n)\n\nfunc main() {\n\thettyCmd, cfg := NewHettyCommand()\n\n\tif err := hettyCmd.Parse(os.Args[1:]); err != nil {\n\t\tllog.Fatalf(\"Failed to parse command line arguments: %v\", err)\n\t}\n\n\tlogger, err := log.NewZapLogger(cfg.verbose, cfg.jsonLogs)\n\tif err != nil {\n\t\tllog.Fatal(err)\n\t}\n\t//nolint:errcheck\n\tdefer logger.Sync()\n\n\tcfg.logger = logger\n\n\terr = hettyCmd.Run(context.Background())\n\tif err != nil && !errors.Is(err, flag.ErrHelp) {\n\t\tlogger.Fatal(\"Command failed.\", zap.Error(err))\n\t}\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/dstotijn/hetty\n\ngo 1.23\n\ntoolchain go1.23.4\n\nrequire (\n\tgithub.com/99designs/gqlgen v0.14.0\n\tgithub.com/chromedp/chromedp v0.7.8\n\tgithub.com/google/go-cmp v0.5.6\n\tgithub.com/gorilla/mux v1.7.4\n\tgithub.com/mitchellh/go-homedir v1.1.0\n\tgithub.com/oklog/ulid v1.3.1\n\tgithub.com/peterbourgon/ff/v3 v3.1.2\n\tgithub.com/smallstep/truststore v0.11.0\n\tgithub.com/vektah/gqlparser/v2 v2.2.0\n\tgo.etcd.io/bbolt v1.4.0-beta.0\n\tgo.uber.org/zap v1.21.0\n)\n\nrequire (\n\tgithub.com/agnivade/levenshtein v1.1.0 // indirect\n\tgithub.com/chromedp/cdproto v0.0.0-20220217222649-d8c14a5c6edf // indirect\n\tgithub.com/chromedp/sysutil v1.0.0 // indirect\n\tgithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect\n\tgithub.com/gobwas/httphead v0.1.0 // indirect\n\tgithub.com/gobwas/pool v0.2.1 // indirect\n\tgithub.com/gobwas/ws v1.1.0 // indirect\n\tgithub.com/gorilla/websocket v1.4.2 // indirect\n\tgithub.com/hashicorp/golang-lru v0.5.1 // indirect\n\tgithub.com/josharian/intern v1.0.0 // indirect\n\tgithub.com/mailru/easyjson v0.7.7 // indirect\n\tgithub.com/matryer/moq v0.2.5 // indirect\n\tgithub.com/mitchellh/mapstructure v1.1.2 // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/russross/blackfriday/v2 v2.0.1 // indirect\n\tgithub.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect\n\tgithub.com/urfave/cli/v2 v2.1.1 // indirect\n\tgithub.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e // indirect\n\tgo.uber.org/atomic v1.7.0 // indirect\n\tgo.uber.org/multierr v1.6.0 // indirect\n\tgolang.org/x/mod v0.4.2 // indirect\n\tgolang.org/x/sys v0.26.0 // indirect\n\tgolang.org/x/tools v0.1.5 // indirect\n\tgolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect\n\tgopkg.in/yaml.v2 v2.2.8 // indirect\n\thowett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/99designs/gqlgen v0.14.0 h1:Wg8aNYQUjMR/4v+W3xD+7SizOy6lSvVeQ06AobNQAXI=\ngithub.com/99designs/gqlgen v0.14.0/go.mod h1:S7z4boV+Nx4VvzMUpVrY/YuHjFX4n7rDyuTqvAkuoRE=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=\ngithub.com/agnivade/levenshtein v1.1.0 h1:n6qGwyHG61v3ABce1rPVZklEYRT8NFpCMrpZdBUbYGM=\ngithub.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=\ngithub.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=\ngithub.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=\ngithub.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=\ngithub.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=\ngithub.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=\ngithub.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=\ngithub.com/chromedp/cdproto v0.0.0-20220217222649-d8c14a5c6edf h1:1omDWNUsWxn2HpiMiMuyRmzjl9uG7RP3IE6GTlpgJWU=\ngithub.com/chromedp/cdproto v0.0.0-20220217222649-d8c14a5c6edf/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=\ngithub.com/chromedp/chromedp v0.7.8 h1:JFPIFb28LPjcx6l6mUUzLOTD/TgswcTtg7KrDn8S/2I=\ngithub.com/chromedp/chromedp v0.7.8/go.mod h1:HcIUFBa5vA+u2QI3+xljiU59llUQ8lgGoLzYSCBfmUA=\ngithub.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=\ngithub.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=\ngithub.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=\ngithub.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=\ngithub.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=\ngithub.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=\ngithub.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=\ngithub.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=\ngithub.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=\ngithub.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=\ngithub.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=\ngithub.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=\ngithub.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=\ngithub.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=\ngithub.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=\ngithub.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=\ngithub.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=\ngithub.com/matryer/moq v0.2.5 h1:BGQISyhl7Gc9W/gMYmAJONh9mT6AYeyeTjNupNPknMs=\ngithub.com/matryer/moq v0.2.5/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE=\ngithub.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=\ngithub.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=\ngithub.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=\ngithub.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=\ngithub.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=\ngithub.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=\ngithub.com/peterbourgon/ff/v3 v3.1.2 h1:0GNhbRhO9yHA4CC27ymskOsuRpmX0YQxwxM9UPiP6JM=\ngithub.com/peterbourgon/ff/v3 v3.1.2/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=\ngithub.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=\ngithub.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=\ngithub.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=\ngithub.com/smallstep/truststore v0.11.0 h1:JUTkQ4oHr40jHTS/A2t0usEhteMWG+45CDD2iJA/dIk=\ngithub.com/smallstep/truststore v0.11.0/go.mod h1:HwHKRcBi0RUxxw1LYDpTRhYC4jZUuxPpkHdVonlkoDM=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=\ngithub.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=\ngithub.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=\ngithub.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg=\ngithub.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=\ngithub.com/vektah/gqlparser/v2 v2.2.0 h1:bAc3slekAAJW6sZTi07aGq0OrfaCjj4jxARAaC7g2EM=\ngithub.com/vektah/gqlparser/v2 v2.2.0/go.mod h1:i3mQIGIrbK2PD1RrCeMTlVbkF2FJ6WkU1KJlJlC+3F4=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngo.etcd.io/bbolt v1.4.0-beta.0 h1:U7Y9yH6ZojEo5/BDFMXDXD1RNx9L7iKxudzqR68jLaM=\ngo.etcd.io/bbolt v1.4.0-beta.0/go.mod h1:Qv5yHB6jkQESXT/uVfxJgUPMqgAyhL0GLxcQaz9bSec=\ngo.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=\ngo.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=\ngo.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=\ngo.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=\ngolang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=\ngolang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=\ngolang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhowett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M=\nhowett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=\nsourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=\nsourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=\n"
  },
  {
    "path": "gqlgen.yml",
    "content": "# Where are all the schema files located? globs are supported eg  src/**/*.graphqls\nschema:\n  - pkg/api/schema.graphql\n\n# Where should the generated server code go?\nexec:\n  filename: pkg/api/generated.go\n  package: api\n\n# Uncomment to enable federation\n# federation:\n#   filename: graph/generated/federation.go\n#   package: generated\n\n# Where should any generated models go?\nmodel:\n  filename: pkg/api/models_gen.go\n  package: api\n\n# Where should the resolver implementations go?\nresolver:\n  layout: single-file\n  filename: pkg/api/resolvers.go\n  dir: pkg/api\n  package: api\n\n# Optional: turn on use `gqlgen:\"fieldName\"` tags in your models\n# struct_tag: json\n\n# Optional: turn on to use []Thing instead of []*Thing\nomit_slice_element_pointers: true\n# Optional: set to speed up generation time by not performing a final validation pass.\n# skip_validation: true\n\n# gqlgen will search for any type names in the schema in these go packages\n# if they match it will use them, otherwise it will generate them.\n# autobind:\n#   - \"github.com/dstotijn/hetty/graph/model\"\n\n# This section declares type mapping between the GraphQL and go type systems\n#\n# The first line in each type will be used as defaults for resolver arguments and\n# modelgen, the others will be allowed when binding to fields. Configure them to\n# your liking\nmodels:\n  ID:\n    model:\n      - github.com/dstotijn/hetty/pkg/api.ULID\n  URL:\n    model:\n      - github.com/dstotijn/hetty/pkg/api.URL\n#   Int:\n#     model:\n#       - github.com/99designs/gqlgen/graphql.Int\n#       - github.com/99designs/gqlgen/graphql.Int64\n#       - github.com/99designs/gqlgen/graphql.Int32\n"
  },
  {
    "path": "pkg/api/generated.go",
    "content": "// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.\n\npackage api\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/99designs/gqlgen/graphql\"\n\t\"github.com/99designs/gqlgen/graphql/introspection\"\n\t\"github.com/oklog/ulid\"\n\tgqlparser \"github.com/vektah/gqlparser/v2\"\n\t\"github.com/vektah/gqlparser/v2/ast\"\n)\n\n// region    ************************** generated!.gotpl **************************\n\n// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.\nfunc NewExecutableSchema(cfg Config) graphql.ExecutableSchema {\n\treturn &executableSchema{\n\t\tresolvers:  cfg.Resolvers,\n\t\tdirectives: cfg.Directives,\n\t\tcomplexity: cfg.Complexity,\n\t}\n}\n\ntype Config struct {\n\tResolvers  ResolverRoot\n\tDirectives DirectiveRoot\n\tComplexity ComplexityRoot\n}\n\ntype ResolverRoot interface {\n\tMutation() MutationResolver\n\tQuery() QueryResolver\n}\n\ntype DirectiveRoot struct {\n}\n\ntype ComplexityRoot struct {\n\tCancelRequestResult struct {\n\t\tSuccess func(childComplexity int) int\n\t}\n\n\tCancelResponseResult struct {\n\t\tSuccess func(childComplexity int) int\n\t}\n\n\tClearHTTPRequestLogResult struct {\n\t\tSuccess func(childComplexity int) int\n\t}\n\n\tCloseProjectResult struct {\n\t\tSuccess func(childComplexity int) int\n\t}\n\n\tDeleteProjectResult struct {\n\t\tSuccess func(childComplexity int) int\n\t}\n\n\tDeleteSenderRequestsResult struct {\n\t\tSuccess func(childComplexity int) int\n\t}\n\n\tHTTPHeader struct {\n\t\tKey   func(childComplexity int) int\n\t\tValue func(childComplexity int) int\n\t}\n\n\tHTTPRequest struct {\n\t\tBody     func(childComplexity int) int\n\t\tHeaders  func(childComplexity int) int\n\t\tID       func(childComplexity int) int\n\t\tMethod   func(childComplexity int) int\n\t\tProto    func(childComplexity int) int\n\t\tResponse func(childComplexity int) int\n\t\tURL      func(childComplexity int) int\n\t}\n\n\tHTTPRequestLog struct {\n\t\tBody      func(childComplexity int) int\n\t\tHeaders   func(childComplexity int) int\n\t\tID        func(childComplexity int) int\n\t\tMethod    func(childComplexity int) int\n\t\tProto     func(childComplexity int) int\n\t\tResponse  func(childComplexity int) int\n\t\tTimestamp func(childComplexity int) int\n\t\tURL       func(childComplexity int) int\n\t}\n\n\tHTTPRequestLogFilter struct {\n\t\tOnlyInScope      func(childComplexity int) int\n\t\tSearchExpression func(childComplexity int) int\n\t}\n\n\tHTTPResponse struct {\n\t\tBody         func(childComplexity int) int\n\t\tHeaders      func(childComplexity int) int\n\t\tID           func(childComplexity int) int\n\t\tProto        func(childComplexity int) int\n\t\tStatusCode   func(childComplexity int) int\n\t\tStatusReason func(childComplexity int) int\n\t}\n\n\tHTTPResponseLog struct {\n\t\tBody         func(childComplexity int) int\n\t\tHeaders      func(childComplexity int) int\n\t\tID           func(childComplexity int) int\n\t\tProto        func(childComplexity int) int\n\t\tStatusCode   func(childComplexity int) int\n\t\tStatusReason func(childComplexity int) int\n\t}\n\n\tInterceptSettings struct {\n\t\tRequestFilter    func(childComplexity int) int\n\t\tRequestsEnabled  func(childComplexity int) int\n\t\tResponseFilter   func(childComplexity int) int\n\t\tResponsesEnabled func(childComplexity int) int\n\t}\n\n\tModifyRequestResult struct {\n\t\tSuccess func(childComplexity int) int\n\t}\n\n\tModifyResponseResult struct {\n\t\tSuccess func(childComplexity int) int\n\t}\n\n\tMutation struct {\n\t\tCancelRequest                         func(childComplexity int, id ulid.ULID) int\n\t\tCancelResponse                        func(childComplexity int, requestID ulid.ULID) int\n\t\tClearHTTPRequestLog                   func(childComplexity int) int\n\t\tCloseProject                          func(childComplexity int) int\n\t\tCreateOrUpdateSenderRequest           func(childComplexity int, request SenderRequestInput) int\n\t\tCreateProject                         func(childComplexity int, name string) int\n\t\tCreateSenderRequestFromHTTPRequestLog func(childComplexity int, id ulid.ULID) int\n\t\tDeleteProject                         func(childComplexity int, id ulid.ULID) int\n\t\tDeleteSenderRequests                  func(childComplexity int) int\n\t\tModifyRequest                         func(childComplexity int, request ModifyRequestInput) int\n\t\tModifyResponse                        func(childComplexity int, response ModifyResponseInput) int\n\t\tOpenProject                           func(childComplexity int, id ulid.ULID) int\n\t\tSendRequest                           func(childComplexity int, id ulid.ULID) int\n\t\tSetHTTPRequestLogFilter               func(childComplexity int, filter *HTTPRequestLogFilterInput) int\n\t\tSetScope                              func(childComplexity int, scope []ScopeRuleInput) int\n\t\tSetSenderRequestFilter                func(childComplexity int, filter *SenderRequestFilterInput) int\n\t\tUpdateInterceptSettings               func(childComplexity int, input UpdateInterceptSettingsInput) int\n\t}\n\n\tProject struct {\n\t\tID       func(childComplexity int) int\n\t\tIsActive func(childComplexity int) int\n\t\tName     func(childComplexity int) int\n\t\tSettings func(childComplexity int) int\n\t}\n\n\tProjectSettings struct {\n\t\tIntercept func(childComplexity int) int\n\t}\n\n\tQuery struct {\n\t\tActiveProject        func(childComplexity int) int\n\t\tHTTPRequestLog       func(childComplexity int, id ulid.ULID) int\n\t\tHTTPRequestLogFilter func(childComplexity int) int\n\t\tHTTPRequestLogs      func(childComplexity int) int\n\t\tInterceptedRequest   func(childComplexity int, id ulid.ULID) int\n\t\tInterceptedRequests  func(childComplexity int) int\n\t\tProjects             func(childComplexity int) int\n\t\tScope                func(childComplexity int) int\n\t\tSenderRequest        func(childComplexity int, id ulid.ULID) int\n\t\tSenderRequests       func(childComplexity int) int\n\t}\n\n\tScopeHeader struct {\n\t\tKey   func(childComplexity int) int\n\t\tValue func(childComplexity int) int\n\t}\n\n\tScopeRule struct {\n\t\tBody   func(childComplexity int) int\n\t\tHeader func(childComplexity int) int\n\t\tURL    func(childComplexity int) int\n\t}\n\n\tSenderRequest struct {\n\t\tBody               func(childComplexity int) int\n\t\tHeaders            func(childComplexity int) int\n\t\tID                 func(childComplexity int) int\n\t\tMethod             func(childComplexity int) int\n\t\tProto              func(childComplexity int) int\n\t\tResponse           func(childComplexity int) int\n\t\tSourceRequestLogID func(childComplexity int) int\n\t\tTimestamp          func(childComplexity int) int\n\t\tURL                func(childComplexity int) int\n\t}\n\n\tSenderRequestFilter struct {\n\t\tOnlyInScope      func(childComplexity int) int\n\t\tSearchExpression func(childComplexity int) int\n\t}\n}\n\ntype MutationResolver interface {\n\tCreateProject(ctx context.Context, name string) (*Project, error)\n\tOpenProject(ctx context.Context, id ulid.ULID) (*Project, error)\n\tCloseProject(ctx context.Context) (*CloseProjectResult, error)\n\tDeleteProject(ctx context.Context, id ulid.ULID) (*DeleteProjectResult, error)\n\tClearHTTPRequestLog(ctx context.Context) (*ClearHTTPRequestLogResult, error)\n\tSetScope(ctx context.Context, scope []ScopeRuleInput) ([]ScopeRule, error)\n\tSetHTTPRequestLogFilter(ctx context.Context, filter *HTTPRequestLogFilterInput) (*HTTPRequestLogFilter, error)\n\tSetSenderRequestFilter(ctx context.Context, filter *SenderRequestFilterInput) (*SenderRequestFilter, error)\n\tCreateOrUpdateSenderRequest(ctx context.Context, request SenderRequestInput) (*SenderRequest, error)\n\tCreateSenderRequestFromHTTPRequestLog(ctx context.Context, id ulid.ULID) (*SenderRequest, error)\n\tSendRequest(ctx context.Context, id ulid.ULID) (*SenderRequest, error)\n\tDeleteSenderRequests(ctx context.Context) (*DeleteSenderRequestsResult, error)\n\tModifyRequest(ctx context.Context, request ModifyRequestInput) (*ModifyRequestResult, error)\n\tCancelRequest(ctx context.Context, id ulid.ULID) (*CancelRequestResult, error)\n\tModifyResponse(ctx context.Context, response ModifyResponseInput) (*ModifyResponseResult, error)\n\tCancelResponse(ctx context.Context, requestID ulid.ULID) (*CancelResponseResult, error)\n\tUpdateInterceptSettings(ctx context.Context, input UpdateInterceptSettingsInput) (*InterceptSettings, error)\n}\ntype QueryResolver interface {\n\tHTTPRequestLog(ctx context.Context, id ulid.ULID) (*HTTPRequestLog, error)\n\tHTTPRequestLogs(ctx context.Context) ([]HTTPRequestLog, error)\n\tHTTPRequestLogFilter(ctx context.Context) (*HTTPRequestLogFilter, error)\n\tActiveProject(ctx context.Context) (*Project, error)\n\tProjects(ctx context.Context) ([]Project, error)\n\tScope(ctx context.Context) ([]ScopeRule, error)\n\tSenderRequest(ctx context.Context, id ulid.ULID) (*SenderRequest, error)\n\tSenderRequests(ctx context.Context) ([]SenderRequest, error)\n\tInterceptedRequests(ctx context.Context) ([]HTTPRequest, error)\n\tInterceptedRequest(ctx context.Context, id ulid.ULID) (*HTTPRequest, error)\n}\n\ntype executableSchema struct {\n\tresolvers  ResolverRoot\n\tdirectives DirectiveRoot\n\tcomplexity ComplexityRoot\n}\n\nfunc (e *executableSchema) Schema() *ast.Schema {\n\treturn parsedSchema\n}\n\nfunc (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {\n\tec := executionContext{nil, e}\n\t_ = ec\n\tswitch typeName + \".\" + field {\n\n\tcase \"CancelRequestResult.success\":\n\t\tif e.complexity.CancelRequestResult.Success == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.CancelRequestResult.Success(childComplexity), true\n\n\tcase \"CancelResponseResult.success\":\n\t\tif e.complexity.CancelResponseResult.Success == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.CancelResponseResult.Success(childComplexity), true\n\n\tcase \"ClearHTTPRequestLogResult.success\":\n\t\tif e.complexity.ClearHTTPRequestLogResult.Success == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.ClearHTTPRequestLogResult.Success(childComplexity), true\n\n\tcase \"CloseProjectResult.success\":\n\t\tif e.complexity.CloseProjectResult.Success == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.CloseProjectResult.Success(childComplexity), true\n\n\tcase \"DeleteProjectResult.success\":\n\t\tif e.complexity.DeleteProjectResult.Success == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.DeleteProjectResult.Success(childComplexity), true\n\n\tcase \"DeleteSenderRequestsResult.success\":\n\t\tif e.complexity.DeleteSenderRequestsResult.Success == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.DeleteSenderRequestsResult.Success(childComplexity), true\n\n\tcase \"HttpHeader.key\":\n\t\tif e.complexity.HTTPHeader.Key == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPHeader.Key(childComplexity), true\n\n\tcase \"HttpHeader.value\":\n\t\tif e.complexity.HTTPHeader.Value == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPHeader.Value(childComplexity), true\n\n\tcase \"HttpRequest.body\":\n\t\tif e.complexity.HTTPRequest.Body == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequest.Body(childComplexity), true\n\n\tcase \"HttpRequest.headers\":\n\t\tif e.complexity.HTTPRequest.Headers == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequest.Headers(childComplexity), true\n\n\tcase \"HttpRequest.id\":\n\t\tif e.complexity.HTTPRequest.ID == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequest.ID(childComplexity), true\n\n\tcase \"HttpRequest.method\":\n\t\tif e.complexity.HTTPRequest.Method == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequest.Method(childComplexity), true\n\n\tcase \"HttpRequest.proto\":\n\t\tif e.complexity.HTTPRequest.Proto == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequest.Proto(childComplexity), true\n\n\tcase \"HttpRequest.response\":\n\t\tif e.complexity.HTTPRequest.Response == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequest.Response(childComplexity), true\n\n\tcase \"HttpRequest.url\":\n\t\tif e.complexity.HTTPRequest.URL == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequest.URL(childComplexity), true\n\n\tcase \"HttpRequestLog.body\":\n\t\tif e.complexity.HTTPRequestLog.Body == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequestLog.Body(childComplexity), true\n\n\tcase \"HttpRequestLog.headers\":\n\t\tif e.complexity.HTTPRequestLog.Headers == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequestLog.Headers(childComplexity), true\n\n\tcase \"HttpRequestLog.id\":\n\t\tif e.complexity.HTTPRequestLog.ID == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequestLog.ID(childComplexity), true\n\n\tcase \"HttpRequestLog.method\":\n\t\tif e.complexity.HTTPRequestLog.Method == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequestLog.Method(childComplexity), true\n\n\tcase \"HttpRequestLog.proto\":\n\t\tif e.complexity.HTTPRequestLog.Proto == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequestLog.Proto(childComplexity), true\n\n\tcase \"HttpRequestLog.response\":\n\t\tif e.complexity.HTTPRequestLog.Response == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequestLog.Response(childComplexity), true\n\n\tcase \"HttpRequestLog.timestamp\":\n\t\tif e.complexity.HTTPRequestLog.Timestamp == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequestLog.Timestamp(childComplexity), true\n\n\tcase \"HttpRequestLog.url\":\n\t\tif e.complexity.HTTPRequestLog.URL == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequestLog.URL(childComplexity), true\n\n\tcase \"HttpRequestLogFilter.onlyInScope\":\n\t\tif e.complexity.HTTPRequestLogFilter.OnlyInScope == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequestLogFilter.OnlyInScope(childComplexity), true\n\n\tcase \"HttpRequestLogFilter.searchExpression\":\n\t\tif e.complexity.HTTPRequestLogFilter.SearchExpression == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPRequestLogFilter.SearchExpression(childComplexity), true\n\n\tcase \"HttpResponse.body\":\n\t\tif e.complexity.HTTPResponse.Body == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponse.Body(childComplexity), true\n\n\tcase \"HttpResponse.headers\":\n\t\tif e.complexity.HTTPResponse.Headers == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponse.Headers(childComplexity), true\n\n\tcase \"HttpResponse.id\":\n\t\tif e.complexity.HTTPResponse.ID == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponse.ID(childComplexity), true\n\n\tcase \"HttpResponse.proto\":\n\t\tif e.complexity.HTTPResponse.Proto == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponse.Proto(childComplexity), true\n\n\tcase \"HttpResponse.statusCode\":\n\t\tif e.complexity.HTTPResponse.StatusCode == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponse.StatusCode(childComplexity), true\n\n\tcase \"HttpResponse.statusReason\":\n\t\tif e.complexity.HTTPResponse.StatusReason == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponse.StatusReason(childComplexity), true\n\n\tcase \"HttpResponseLog.body\":\n\t\tif e.complexity.HTTPResponseLog.Body == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponseLog.Body(childComplexity), true\n\n\tcase \"HttpResponseLog.headers\":\n\t\tif e.complexity.HTTPResponseLog.Headers == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponseLog.Headers(childComplexity), true\n\n\tcase \"HttpResponseLog.id\":\n\t\tif e.complexity.HTTPResponseLog.ID == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponseLog.ID(childComplexity), true\n\n\tcase \"HttpResponseLog.proto\":\n\t\tif e.complexity.HTTPResponseLog.Proto == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponseLog.Proto(childComplexity), true\n\n\tcase \"HttpResponseLog.statusCode\":\n\t\tif e.complexity.HTTPResponseLog.StatusCode == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponseLog.StatusCode(childComplexity), true\n\n\tcase \"HttpResponseLog.statusReason\":\n\t\tif e.complexity.HTTPResponseLog.StatusReason == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.HTTPResponseLog.StatusReason(childComplexity), true\n\n\tcase \"InterceptSettings.requestFilter\":\n\t\tif e.complexity.InterceptSettings.RequestFilter == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.InterceptSettings.RequestFilter(childComplexity), true\n\n\tcase \"InterceptSettings.requestsEnabled\":\n\t\tif e.complexity.InterceptSettings.RequestsEnabled == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.InterceptSettings.RequestsEnabled(childComplexity), true\n\n\tcase \"InterceptSettings.responseFilter\":\n\t\tif e.complexity.InterceptSettings.ResponseFilter == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.InterceptSettings.ResponseFilter(childComplexity), true\n\n\tcase \"InterceptSettings.responsesEnabled\":\n\t\tif e.complexity.InterceptSettings.ResponsesEnabled == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.InterceptSettings.ResponsesEnabled(childComplexity), true\n\n\tcase \"ModifyRequestResult.success\":\n\t\tif e.complexity.ModifyRequestResult.Success == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.ModifyRequestResult.Success(childComplexity), true\n\n\tcase \"ModifyResponseResult.success\":\n\t\tif e.complexity.ModifyResponseResult.Success == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.ModifyResponseResult.Success(childComplexity), true\n\n\tcase \"Mutation.cancelRequest\":\n\t\tif e.complexity.Mutation.CancelRequest == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_cancelRequest_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.CancelRequest(childComplexity, args[\"id\"].(ulid.ULID)), true\n\n\tcase \"Mutation.cancelResponse\":\n\t\tif e.complexity.Mutation.CancelResponse == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_cancelResponse_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.CancelResponse(childComplexity, args[\"requestID\"].(ulid.ULID)), true\n\n\tcase \"Mutation.clearHTTPRequestLog\":\n\t\tif e.complexity.Mutation.ClearHTTPRequestLog == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Mutation.ClearHTTPRequestLog(childComplexity), true\n\n\tcase \"Mutation.closeProject\":\n\t\tif e.complexity.Mutation.CloseProject == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Mutation.CloseProject(childComplexity), true\n\n\tcase \"Mutation.createOrUpdateSenderRequest\":\n\t\tif e.complexity.Mutation.CreateOrUpdateSenderRequest == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_createOrUpdateSenderRequest_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.CreateOrUpdateSenderRequest(childComplexity, args[\"request\"].(SenderRequestInput)), true\n\n\tcase \"Mutation.createProject\":\n\t\tif e.complexity.Mutation.CreateProject == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_createProject_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.CreateProject(childComplexity, args[\"name\"].(string)), true\n\n\tcase \"Mutation.createSenderRequestFromHttpRequestLog\":\n\t\tif e.complexity.Mutation.CreateSenderRequestFromHTTPRequestLog == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_createSenderRequestFromHttpRequestLog_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.CreateSenderRequestFromHTTPRequestLog(childComplexity, args[\"id\"].(ulid.ULID)), true\n\n\tcase \"Mutation.deleteProject\":\n\t\tif e.complexity.Mutation.DeleteProject == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_deleteProject_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.DeleteProject(childComplexity, args[\"id\"].(ulid.ULID)), true\n\n\tcase \"Mutation.deleteSenderRequests\":\n\t\tif e.complexity.Mutation.DeleteSenderRequests == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Mutation.DeleteSenderRequests(childComplexity), true\n\n\tcase \"Mutation.modifyRequest\":\n\t\tif e.complexity.Mutation.ModifyRequest == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_modifyRequest_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.ModifyRequest(childComplexity, args[\"request\"].(ModifyRequestInput)), true\n\n\tcase \"Mutation.modifyResponse\":\n\t\tif e.complexity.Mutation.ModifyResponse == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_modifyResponse_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.ModifyResponse(childComplexity, args[\"response\"].(ModifyResponseInput)), true\n\n\tcase \"Mutation.openProject\":\n\t\tif e.complexity.Mutation.OpenProject == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_openProject_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.OpenProject(childComplexity, args[\"id\"].(ulid.ULID)), true\n\n\tcase \"Mutation.sendRequest\":\n\t\tif e.complexity.Mutation.SendRequest == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_sendRequest_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.SendRequest(childComplexity, args[\"id\"].(ulid.ULID)), true\n\n\tcase \"Mutation.setHttpRequestLogFilter\":\n\t\tif e.complexity.Mutation.SetHTTPRequestLogFilter == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_setHttpRequestLogFilter_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.SetHTTPRequestLogFilter(childComplexity, args[\"filter\"].(*HTTPRequestLogFilterInput)), true\n\n\tcase \"Mutation.setScope\":\n\t\tif e.complexity.Mutation.SetScope == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_setScope_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.SetScope(childComplexity, args[\"scope\"].([]ScopeRuleInput)), true\n\n\tcase \"Mutation.setSenderRequestFilter\":\n\t\tif e.complexity.Mutation.SetSenderRequestFilter == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_setSenderRequestFilter_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.SetSenderRequestFilter(childComplexity, args[\"filter\"].(*SenderRequestFilterInput)), true\n\n\tcase \"Mutation.updateInterceptSettings\":\n\t\tif e.complexity.Mutation.UpdateInterceptSettings == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Mutation_updateInterceptSettings_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Mutation.UpdateInterceptSettings(childComplexity, args[\"input\"].(UpdateInterceptSettingsInput)), true\n\n\tcase \"Project.id\":\n\t\tif e.complexity.Project.ID == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Project.ID(childComplexity), true\n\n\tcase \"Project.isActive\":\n\t\tif e.complexity.Project.IsActive == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Project.IsActive(childComplexity), true\n\n\tcase \"Project.name\":\n\t\tif e.complexity.Project.Name == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Project.Name(childComplexity), true\n\n\tcase \"Project.settings\":\n\t\tif e.complexity.Project.Settings == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Project.Settings(childComplexity), true\n\n\tcase \"ProjectSettings.intercept\":\n\t\tif e.complexity.ProjectSettings.Intercept == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.ProjectSettings.Intercept(childComplexity), true\n\n\tcase \"Query.activeProject\":\n\t\tif e.complexity.Query.ActiveProject == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Query.ActiveProject(childComplexity), true\n\n\tcase \"Query.httpRequestLog\":\n\t\tif e.complexity.Query.HTTPRequestLog == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Query_httpRequestLog_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Query.HTTPRequestLog(childComplexity, args[\"id\"].(ulid.ULID)), true\n\n\tcase \"Query.httpRequestLogFilter\":\n\t\tif e.complexity.Query.HTTPRequestLogFilter == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Query.HTTPRequestLogFilter(childComplexity), true\n\n\tcase \"Query.httpRequestLogs\":\n\t\tif e.complexity.Query.HTTPRequestLogs == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Query.HTTPRequestLogs(childComplexity), true\n\n\tcase \"Query.interceptedRequest\":\n\t\tif e.complexity.Query.InterceptedRequest == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Query_interceptedRequest_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Query.InterceptedRequest(childComplexity, args[\"id\"].(ulid.ULID)), true\n\n\tcase \"Query.interceptedRequests\":\n\t\tif e.complexity.Query.InterceptedRequests == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Query.InterceptedRequests(childComplexity), true\n\n\tcase \"Query.projects\":\n\t\tif e.complexity.Query.Projects == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Query.Projects(childComplexity), true\n\n\tcase \"Query.scope\":\n\t\tif e.complexity.Query.Scope == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Query.Scope(childComplexity), true\n\n\tcase \"Query.senderRequest\":\n\t\tif e.complexity.Query.SenderRequest == nil {\n\t\t\tbreak\n\t\t}\n\n\t\targs, err := ec.field_Query_senderRequest_args(context.TODO(), rawArgs)\n\t\tif err != nil {\n\t\t\treturn 0, false\n\t\t}\n\n\t\treturn e.complexity.Query.SenderRequest(childComplexity, args[\"id\"].(ulid.ULID)), true\n\n\tcase \"Query.senderRequests\":\n\t\tif e.complexity.Query.SenderRequests == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.Query.SenderRequests(childComplexity), true\n\n\tcase \"ScopeHeader.key\":\n\t\tif e.complexity.ScopeHeader.Key == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.ScopeHeader.Key(childComplexity), true\n\n\tcase \"ScopeHeader.value\":\n\t\tif e.complexity.ScopeHeader.Value == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.ScopeHeader.Value(childComplexity), true\n\n\tcase \"ScopeRule.body\":\n\t\tif e.complexity.ScopeRule.Body == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.ScopeRule.Body(childComplexity), true\n\n\tcase \"ScopeRule.header\":\n\t\tif e.complexity.ScopeRule.Header == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.ScopeRule.Header(childComplexity), true\n\n\tcase \"ScopeRule.url\":\n\t\tif e.complexity.ScopeRule.URL == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.ScopeRule.URL(childComplexity), true\n\n\tcase \"SenderRequest.body\":\n\t\tif e.complexity.SenderRequest.Body == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.SenderRequest.Body(childComplexity), true\n\n\tcase \"SenderRequest.headers\":\n\t\tif e.complexity.SenderRequest.Headers == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.SenderRequest.Headers(childComplexity), true\n\n\tcase \"SenderRequest.id\":\n\t\tif e.complexity.SenderRequest.ID == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.SenderRequest.ID(childComplexity), true\n\n\tcase \"SenderRequest.method\":\n\t\tif e.complexity.SenderRequest.Method == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.SenderRequest.Method(childComplexity), true\n\n\tcase \"SenderRequest.proto\":\n\t\tif e.complexity.SenderRequest.Proto == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.SenderRequest.Proto(childComplexity), true\n\n\tcase \"SenderRequest.response\":\n\t\tif e.complexity.SenderRequest.Response == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.SenderRequest.Response(childComplexity), true\n\n\tcase \"SenderRequest.sourceRequestLogID\":\n\t\tif e.complexity.SenderRequest.SourceRequestLogID == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.SenderRequest.SourceRequestLogID(childComplexity), true\n\n\tcase \"SenderRequest.timestamp\":\n\t\tif e.complexity.SenderRequest.Timestamp == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.SenderRequest.Timestamp(childComplexity), true\n\n\tcase \"SenderRequest.url\":\n\t\tif e.complexity.SenderRequest.URL == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.SenderRequest.URL(childComplexity), true\n\n\tcase \"SenderRequestFilter.onlyInScope\":\n\t\tif e.complexity.SenderRequestFilter.OnlyInScope == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.SenderRequestFilter.OnlyInScope(childComplexity), true\n\n\tcase \"SenderRequestFilter.searchExpression\":\n\t\tif e.complexity.SenderRequestFilter.SearchExpression == nil {\n\t\t\tbreak\n\t\t}\n\n\t\treturn e.complexity.SenderRequestFilter.SearchExpression(childComplexity), true\n\n\t}\n\treturn 0, false\n}\n\nfunc (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {\n\trc := graphql.GetOperationContext(ctx)\n\tec := executionContext{rc, e}\n\tfirst := true\n\n\tswitch rc.Operation.Operation {\n\tcase ast.Query:\n\t\treturn func(ctx context.Context) *graphql.Response {\n\t\t\tif !first {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tfirst = false\n\t\t\tdata := ec._Query(ctx, rc.Operation.SelectionSet)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\n\t\t\treturn &graphql.Response{\n\t\t\t\tData: buf.Bytes(),\n\t\t\t}\n\t\t}\n\tcase ast.Mutation:\n\t\treturn func(ctx context.Context) *graphql.Response {\n\t\t\tif !first {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tfirst = false\n\t\t\tdata := ec._Mutation(ctx, rc.Operation.SelectionSet)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\n\t\t\treturn &graphql.Response{\n\t\t\t\tData: buf.Bytes(),\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\treturn graphql.OneShot(graphql.ErrorResponse(ctx, \"unsupported GraphQL operation\"))\n\t}\n}\n\ntype executionContext struct {\n\t*graphql.OperationContext\n\t*executableSchema\n}\n\nfunc (ec *executionContext) introspectSchema() (*introspection.Schema, error) {\n\tif ec.DisableIntrospection {\n\t\treturn nil, errors.New(\"introspection disabled\")\n\t}\n\treturn introspection.WrapSchema(parsedSchema), nil\n}\n\nfunc (ec *executionContext) introspectType(name string) (*introspection.Type, error) {\n\tif ec.DisableIntrospection {\n\t\treturn nil, errors.New(\"introspection disabled\")\n\t}\n\treturn introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil\n}\n\nvar sources = []*ast.Source{\n\t{Name: \"pkg/api/schema.graphql\", Input: `type HttpRequestLog {\n  id: ID!\n  url: String!\n  method: HttpMethod!\n  proto: String!\n  headers: [HttpHeader!]!\n  body: String\n  timestamp: Time!\n  response: HttpResponseLog\n}\n\ntype HttpResponseLog {\n  \"\"\"\n  Will be the same ID as its related request ID.\n  \"\"\"\n  id: ID!\n  proto: HttpProtocol!\n  statusCode: Int!\n  statusReason: String!\n  body: String\n  headers: [HttpHeader!]!\n}\n\ntype HttpHeader {\n  key: String!\n  value: String!\n}\n\ntype Project {\n  id: ID!\n  name: String!\n  isActive: Boolean!\n  settings: ProjectSettings!\n}\n\ntype ProjectSettings {\n  intercept: InterceptSettings!\n}\n\ntype ScopeRule {\n  url: Regexp\n  header: ScopeHeader\n  body: Regexp\n}\n\ninput ScopeRuleInput {\n  url: Regexp\n  header: ScopeHeaderInput\n  body: Regexp\n}\n\ntype ScopeHeader {\n  key: Regexp\n  value: Regexp\n}\n\ninput ScopeHeaderInput {\n  key: Regexp\n  value: Regexp\n}\n\ntype CloseProjectResult {\n  success: Boolean!\n}\n\ntype DeleteProjectResult {\n  success: Boolean!\n}\n\ntype ClearHTTPRequestLogResult {\n  success: Boolean!\n}\n\ntype DeleteSenderRequestsResult {\n  success: Boolean!\n}\n\ninput HttpRequestLogFilterInput {\n  onlyInScope: Boolean\n  searchExpression: String\n}\n\ntype HttpRequestLogFilter {\n  onlyInScope: Boolean!\n  searchExpression: String\n}\n\ninput SenderRequestInput {\n  id: ID\n  url: URL!\n  method: HttpMethod\n  proto: HttpProtocol\n  headers: [HttpHeaderInput!]\n  body: String\n}\n\ninput HttpHeaderInput {\n  key: String!\n  value: String!\n}\n\ntype SenderRequest {\n  id: ID!\n  sourceRequestLogID: ID\n  url: URL!\n  method: HttpMethod!\n  proto: HttpProtocol!\n  headers: [HttpHeader!]\n  body: String\n  timestamp: Time!\n  response: HttpResponseLog\n}\n\ninput SenderRequestFilterInput {\n  onlyInScope: Boolean\n  searchExpression: String\n}\n\ntype SenderRequestFilter {\n  onlyInScope: Boolean!\n  searchExpression: String\n}\n\ntype HttpRequest {\n  id: ID!\n  url: URL!\n  method: HttpMethod!\n  proto: HttpProtocol!\n  headers: [HttpHeader!]!\n  body: String\n  response: HttpResponse\n}\n\ntype HttpResponse {\n  \"\"\"\n  Will be the same ID as its related request ID.\n  \"\"\"\n  id: ID!\n  proto: HttpProtocol!\n  statusCode: Int!\n  statusReason: String!\n  body: String\n  headers: [HttpHeader!]!\n}\n\ninput ModifyRequestInput {\n  id: ID!\n  url: URL!\n  method: HttpMethod!\n  proto: HttpProtocol!\n  headers: [HttpHeaderInput!]\n  body: String\n  modifyResponse: Boolean\n}\n\ntype ModifyRequestResult {\n  success: Boolean!\n}\n\ntype CancelRequestResult {\n  success: Boolean!\n}\n\ninput ModifyResponseInput {\n  requestID: ID!\n  proto: HttpProtocol!\n  headers: [HttpHeaderInput!]\n  body: String\n  statusCode: Int!\n  statusReason: String!\n}\n\ntype ModifyResponseResult {\n  success: Boolean!\n}\n\ntype CancelResponseResult {\n  success: Boolean!\n}\n\ninput UpdateInterceptSettingsInput {\n  requestsEnabled: Boolean!\n  responsesEnabled: Boolean!\n  requestFilter: String\n  responseFilter: String\n}\n\ntype InterceptSettings {\n  requestsEnabled: Boolean!\n  responsesEnabled: Boolean!\n  requestFilter: String\n  responseFilter: String\n}\n\ntype Query {\n  httpRequestLog(id: ID!): HttpRequestLog\n  httpRequestLogs: [HttpRequestLog!]!\n  httpRequestLogFilter: HttpRequestLogFilter\n  activeProject: Project\n  projects: [Project!]!\n  scope: [ScopeRule!]!\n  senderRequest(id: ID!): SenderRequest\n  senderRequests: [SenderRequest!]!\n  interceptedRequests: [HttpRequest!]!\n  interceptedRequest(id: ID!): HttpRequest\n}\n\ntype Mutation {\n  createProject(name: String!): Project\n  openProject(id: ID!): Project\n  closeProject: CloseProjectResult!\n  deleteProject(id: ID!): DeleteProjectResult!\n  clearHTTPRequestLog: ClearHTTPRequestLogResult!\n  setScope(scope: [ScopeRuleInput!]!): [ScopeRule!]!\n  setHttpRequestLogFilter(\n    filter: HttpRequestLogFilterInput\n  ): HttpRequestLogFilter\n  setSenderRequestFilter(filter: SenderRequestFilterInput): SenderRequestFilter\n  createOrUpdateSenderRequest(request: SenderRequestInput!): SenderRequest!\n  createSenderRequestFromHttpRequestLog(id: ID!): SenderRequest!\n  sendRequest(id: ID!): SenderRequest!\n  deleteSenderRequests: DeleteSenderRequestsResult!\n  modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!\n  cancelRequest(id: ID!): CancelRequestResult!\n  modifyResponse(response: ModifyResponseInput!): ModifyResponseResult!\n  cancelResponse(requestID: ID!): CancelResponseResult!\n  updateInterceptSettings(\n    input: UpdateInterceptSettingsInput!\n  ): InterceptSettings!\n}\n\nenum HttpMethod {\n  GET\n  HEAD\n  POST\n  PUT\n  DELETE\n  CONNECT\n  OPTIONS\n  TRACE\n  PATCH\n}\n\nenum HttpProtocol {\n  HTTP10\n  HTTP11\n  HTTP20\n}\n\nscalar Time\nscalar Regexp\nscalar URL\n`, BuiltIn: false},\n}\nvar parsedSchema = gqlparser.MustLoadSchema(sources...)\n\n// endregion ************************** generated!.gotpl **************************\n\n// region    ***************************** args.gotpl *****************************\n\nfunc (ec *executionContext) field_Mutation_cancelRequest_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 ulid.ULID\n\tif tmp, ok := rawArgs[\"id\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"id\"))\n\t\targ0, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"id\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_cancelResponse_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 ulid.ULID\n\tif tmp, ok := rawArgs[\"requestID\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"requestID\"))\n\t\targ0, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"requestID\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_createOrUpdateSenderRequest_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 SenderRequestInput\n\tif tmp, ok := rawArgs[\"request\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"request\"))\n\t\targ0, err = ec.unmarshalNSenderRequestInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequestInput(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"request\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_createProject_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 string\n\tif tmp, ok := rawArgs[\"name\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"name\"))\n\t\targ0, err = ec.unmarshalNString2string(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"name\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_createSenderRequestFromHttpRequestLog_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 ulid.ULID\n\tif tmp, ok := rawArgs[\"id\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"id\"))\n\t\targ0, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"id\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_deleteProject_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 ulid.ULID\n\tif tmp, ok := rawArgs[\"id\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"id\"))\n\t\targ0, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"id\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_modifyRequest_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 ModifyRequestInput\n\tif tmp, ok := rawArgs[\"request\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"request\"))\n\t\targ0, err = ec.unmarshalNModifyRequestInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyRequestInput(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"request\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_modifyResponse_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 ModifyResponseInput\n\tif tmp, ok := rawArgs[\"response\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"response\"))\n\t\targ0, err = ec.unmarshalNModifyResponseInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyResponseInput(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"response\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_openProject_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 ulid.ULID\n\tif tmp, ok := rawArgs[\"id\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"id\"))\n\t\targ0, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"id\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_sendRequest_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 ulid.ULID\n\tif tmp, ok := rawArgs[\"id\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"id\"))\n\t\targ0, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"id\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_setHttpRequestLogFilter_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 *HTTPRequestLogFilterInput\n\tif tmp, ok := rawArgs[\"filter\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"filter\"))\n\t\targ0, err = ec.unmarshalOHttpRequestLogFilterInput2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestLogFilterInput(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"filter\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_setScope_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 []ScopeRuleInput\n\tif tmp, ok := rawArgs[\"scope\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"scope\"))\n\t\targ0, err = ec.unmarshalNScopeRuleInput2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRuleInputᚄ(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"scope\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_setSenderRequestFilter_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 *SenderRequestFilterInput\n\tif tmp, ok := rawArgs[\"filter\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"filter\"))\n\t\targ0, err = ec.unmarshalOSenderRequestFilterInput2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequestFilterInput(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"filter\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Mutation_updateInterceptSettings_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 UpdateInterceptSettingsInput\n\tif tmp, ok := rawArgs[\"input\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"input\"))\n\t\targ0, err = ec.unmarshalNUpdateInterceptSettingsInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐUpdateInterceptSettingsInput(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"input\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 string\n\tif tmp, ok := rawArgs[\"name\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"name\"))\n\t\targ0, err = ec.unmarshalNString2string(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"name\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Query_httpRequestLog_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 ulid.ULID\n\tif tmp, ok := rawArgs[\"id\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"id\"))\n\t\targ0, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"id\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Query_interceptedRequest_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 ulid.ULID\n\tif tmp, ok := rawArgs[\"id\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"id\"))\n\t\targ0, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"id\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field_Query_senderRequest_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 ulid.ULID\n\tif tmp, ok := rawArgs[\"id\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"id\"))\n\t\targ0, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"id\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 bool\n\tif tmp, ok := rawArgs[\"includeDeprecated\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"includeDeprecated\"))\n\t\targ0, err = ec.unmarshalOBoolean2bool(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"includeDeprecated\"] = arg0\n\treturn args, nil\n}\n\nfunc (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\tvar err error\n\targs := map[string]interface{}{}\n\tvar arg0 bool\n\tif tmp, ok := rawArgs[\"includeDeprecated\"]; ok {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"includeDeprecated\"))\n\t\targ0, err = ec.unmarshalOBoolean2bool(ctx, tmp)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\targs[\"includeDeprecated\"] = arg0\n\treturn args, nil\n}\n\n// endregion ***************************** args.gotpl *****************************\n\n// region    ************************** directives.gotpl **************************\n\n// endregion ************************** directives.gotpl **************************\n\n// region    **************************** field.gotpl *****************************\n\nfunc (ec *executionContext) _CancelRequestResult_success(ctx context.Context, field graphql.CollectedField, obj *CancelRequestResult) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"CancelRequestResult\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Success, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _CancelResponseResult_success(ctx context.Context, field graphql.CollectedField, obj *CancelResponseResult) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"CancelResponseResult\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Success, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _ClearHTTPRequestLogResult_success(ctx context.Context, field graphql.CollectedField, obj *ClearHTTPRequestLogResult) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"ClearHTTPRequestLogResult\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Success, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _CloseProjectResult_success(ctx context.Context, field graphql.CollectedField, obj *CloseProjectResult) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"CloseProjectResult\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Success, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _DeleteProjectResult_success(ctx context.Context, field graphql.CollectedField, obj *DeleteProjectResult) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"DeleteProjectResult\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Success, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _DeleteSenderRequestsResult_success(ctx context.Context, field graphql.CollectedField, obj *DeleteSenderRequestsResult) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"DeleteSenderRequestsResult\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Success, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpHeader_key(ctx context.Context, field graphql.CollectedField, obj *HTTPHeader) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpHeader\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Key, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalNString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpHeader_value(ctx context.Context, field graphql.CollectedField, obj *HTTPHeader) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpHeader\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Value, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalNString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequest_id(ctx context.Context, field graphql.CollectedField, obj *HTTPRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.ID, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(ulid.ULID)\n\tfc.Result = res\n\treturn ec.marshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequest_url(ctx context.Context, field graphql.CollectedField, obj *HTTPRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.URL, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*url.URL)\n\tfc.Result = res\n\treturn ec.marshalNURL2ᚖnetᚋurlᚐURL(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequest_method(ctx context.Context, field graphql.CollectedField, obj *HTTPRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Method, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(HTTPMethod)\n\tfc.Result = res\n\treturn ec.marshalNHttpMethod2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPMethod(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequest_proto(ctx context.Context, field graphql.CollectedField, obj *HTTPRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Proto, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(HTTPProtocol)\n\tfc.Result = res\n\treturn ec.marshalNHttpProtocol2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequest_headers(ctx context.Context, field graphql.CollectedField, obj *HTTPRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Headers, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]HTTPHeader)\n\tfc.Result = res\n\treturn ec.marshalNHttpHeader2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequest_body(ctx context.Context, field graphql.CollectedField, obj *HTTPRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Body, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequest_response(ctx context.Context, field graphql.CollectedField, obj *HTTPRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Response, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*HTTPResponse)\n\tfc.Result = res\n\treturn ec.marshalOHttpResponse2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPResponse(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequestLog_id(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequestLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.ID, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(ulid.ULID)\n\tfc.Result = res\n\treturn ec.marshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequestLog_url(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequestLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.URL, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalNString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequestLog_method(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequestLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Method, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(HTTPMethod)\n\tfc.Result = res\n\treturn ec.marshalNHttpMethod2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPMethod(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequestLog_proto(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequestLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Proto, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalNString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequestLog_headers(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequestLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Headers, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]HTTPHeader)\n\tfc.Result = res\n\treturn ec.marshalNHttpHeader2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequestLog_body(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequestLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Body, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequestLog_timestamp(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequestLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Timestamp, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(time.Time)\n\tfc.Result = res\n\treturn ec.marshalNTime2timeᚐTime(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequestLog_response(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequestLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Response, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*HTTPResponseLog)\n\tfc.Result = res\n\treturn ec.marshalOHttpResponseLog2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPResponseLog(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequestLogFilter_onlyInScope(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLogFilter) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequestLogFilter\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.OnlyInScope, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpRequestLogFilter_searchExpression(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLogFilter) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpRequestLogFilter\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.SearchExpression, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponse_id(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponse\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.ID, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(ulid.ULID)\n\tfc.Result = res\n\treturn ec.marshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponse_proto(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponse\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Proto, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(HTTPProtocol)\n\tfc.Result = res\n\treturn ec.marshalNHttpProtocol2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponse_statusCode(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponse\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.StatusCode, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(int)\n\tfc.Result = res\n\treturn ec.marshalNInt2int(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponse_statusReason(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponse\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.StatusReason, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalNString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponse_body(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponse\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Body, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponse_headers(ctx context.Context, field graphql.CollectedField, obj *HTTPResponse) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponse\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Headers, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]HTTPHeader)\n\tfc.Result = res\n\treturn ec.marshalNHttpHeader2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponseLog_id(ctx context.Context, field graphql.CollectedField, obj *HTTPResponseLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponseLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.ID, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(ulid.ULID)\n\tfc.Result = res\n\treturn ec.marshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponseLog_proto(ctx context.Context, field graphql.CollectedField, obj *HTTPResponseLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponseLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Proto, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(HTTPProtocol)\n\tfc.Result = res\n\treturn ec.marshalNHttpProtocol2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponseLog_statusCode(ctx context.Context, field graphql.CollectedField, obj *HTTPResponseLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponseLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.StatusCode, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(int)\n\tfc.Result = res\n\treturn ec.marshalNInt2int(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponseLog_statusReason(ctx context.Context, field graphql.CollectedField, obj *HTTPResponseLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponseLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.StatusReason, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalNString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponseLog_body(ctx context.Context, field graphql.CollectedField, obj *HTTPResponseLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponseLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Body, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _HttpResponseLog_headers(ctx context.Context, field graphql.CollectedField, obj *HTTPResponseLog) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"HttpResponseLog\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Headers, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]HTTPHeader)\n\tfc.Result = res\n\treturn ec.marshalNHttpHeader2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _InterceptSettings_requestsEnabled(ctx context.Context, field graphql.CollectedField, obj *InterceptSettings) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"InterceptSettings\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.RequestsEnabled, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _InterceptSettings_responsesEnabled(ctx context.Context, field graphql.CollectedField, obj *InterceptSettings) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"InterceptSettings\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.ResponsesEnabled, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _InterceptSettings_requestFilter(ctx context.Context, field graphql.CollectedField, obj *InterceptSettings) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"InterceptSettings\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.RequestFilter, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _InterceptSettings_responseFilter(ctx context.Context, field graphql.CollectedField, obj *InterceptSettings) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"InterceptSettings\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.ResponseFilter, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _ModifyRequestResult_success(ctx context.Context, field graphql.CollectedField, obj *ModifyRequestResult) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"ModifyRequestResult\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Success, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _ModifyResponseResult_success(ctx context.Context, field graphql.CollectedField, obj *ModifyResponseResult) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"ModifyResponseResult\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Success, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_createProject(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_createProject_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().CreateProject(rctx, args[\"name\"].(string))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*Project)\n\tfc.Result = res\n\treturn ec.marshalOProject2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProject(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_openProject(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_openProject_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().OpenProject(rctx, args[\"id\"].(ulid.ULID))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*Project)\n\tfc.Result = res\n\treturn ec.marshalOProject2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProject(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_closeProject(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().CloseProject(rctx)\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*CloseProjectResult)\n\tfc.Result = res\n\treturn ec.marshalNCloseProjectResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCloseProjectResult(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_deleteProject(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_deleteProject_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().DeleteProject(rctx, args[\"id\"].(ulid.ULID))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*DeleteProjectResult)\n\tfc.Result = res\n\treturn ec.marshalNDeleteProjectResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐDeleteProjectResult(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_clearHTTPRequestLog(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().ClearHTTPRequestLog(rctx)\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*ClearHTTPRequestLogResult)\n\tfc.Result = res\n\treturn ec.marshalNClearHTTPRequestLogResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐClearHTTPRequestLogResult(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_setScope(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_setScope_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().SetScope(rctx, args[\"scope\"].([]ScopeRuleInput))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]ScopeRule)\n\tfc.Result = res\n\treturn ec.marshalNScopeRule2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRuleᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_setHttpRequestLogFilter(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_setHttpRequestLogFilter_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().SetHTTPRequestLogFilter(rctx, args[\"filter\"].(*HTTPRequestLogFilterInput))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*HTTPRequestLogFilter)\n\tfc.Result = res\n\treturn ec.marshalOHttpRequestLogFilter2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestLogFilter(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_setSenderRequestFilter(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_setSenderRequestFilter_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().SetSenderRequestFilter(rctx, args[\"filter\"].(*SenderRequestFilterInput))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*SenderRequestFilter)\n\tfc.Result = res\n\treturn ec.marshalOSenderRequestFilter2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequestFilter(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_createOrUpdateSenderRequest(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_createOrUpdateSenderRequest_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().CreateOrUpdateSenderRequest(rctx, args[\"request\"].(SenderRequestInput))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*SenderRequest)\n\tfc.Result = res\n\treturn ec.marshalNSenderRequest2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequest(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_createSenderRequestFromHttpRequestLog(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_createSenderRequestFromHttpRequestLog_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().CreateSenderRequestFromHTTPRequestLog(rctx, args[\"id\"].(ulid.ULID))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*SenderRequest)\n\tfc.Result = res\n\treturn ec.marshalNSenderRequest2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequest(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_sendRequest(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_sendRequest_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().SendRequest(rctx, args[\"id\"].(ulid.ULID))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*SenderRequest)\n\tfc.Result = res\n\treturn ec.marshalNSenderRequest2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequest(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_deleteSenderRequests(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().DeleteSenderRequests(rctx)\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*DeleteSenderRequestsResult)\n\tfc.Result = res\n\treturn ec.marshalNDeleteSenderRequestsResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐDeleteSenderRequestsResult(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_modifyRequest(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_modifyRequest_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().ModifyRequest(rctx, args[\"request\"].(ModifyRequestInput))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*ModifyRequestResult)\n\tfc.Result = res\n\treturn ec.marshalNModifyRequestResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyRequestResult(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_cancelRequest(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_cancelRequest_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().CancelRequest(rctx, args[\"id\"].(ulid.ULID))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*CancelRequestResult)\n\tfc.Result = res\n\treturn ec.marshalNCancelRequestResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelRequestResult(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_modifyResponse(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_modifyResponse_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().ModifyResponse(rctx, args[\"response\"].(ModifyResponseInput))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*ModifyResponseResult)\n\tfc.Result = res\n\treturn ec.marshalNModifyResponseResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyResponseResult(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_cancelResponse(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_cancelResponse_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().CancelResponse(rctx, args[\"requestID\"].(ulid.ULID))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*CancelResponseResult)\n\tfc.Result = res\n\treturn ec.marshalNCancelResponseResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelResponseResult(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Mutation_updateInterceptSettings(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Mutation\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Mutation_updateInterceptSettings_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Mutation().UpdateInterceptSettings(rctx, args[\"input\"].(UpdateInterceptSettingsInput))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*InterceptSettings)\n\tfc.Result = res\n\treturn ec.marshalNInterceptSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Project_id(ctx context.Context, field graphql.CollectedField, obj *Project) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Project\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.ID, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(ulid.ULID)\n\tfc.Result = res\n\treturn ec.marshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Project_name(ctx context.Context, field graphql.CollectedField, obj *Project) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Project\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Name, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalNString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Project_isActive(ctx context.Context, field graphql.CollectedField, obj *Project) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Project\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.IsActive, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Project_settings(ctx context.Context, field graphql.CollectedField, obj *Project) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Project\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Settings, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*ProjectSettings)\n\tfc.Result = res\n\treturn ec.marshalNProjectSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProjectSettings(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _ProjectSettings_intercept(ctx context.Context, field graphql.CollectedField, obj *ProjectSettings) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"ProjectSettings\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Intercept, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*InterceptSettings)\n\tfc.Result = res\n\treturn ec.marshalNInterceptSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query_httpRequestLog(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Query_httpRequestLog_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Query().HTTPRequestLog(rctx, args[\"id\"].(ulid.ULID))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*HTTPRequestLog)\n\tfc.Result = res\n\treturn ec.marshalOHttpRequestLog2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestLog(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query_httpRequestLogs(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Query().HTTPRequestLogs(rctx)\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]HTTPRequestLog)\n\tfc.Result = res\n\treturn ec.marshalNHttpRequestLog2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestLogᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query_httpRequestLogFilter(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Query().HTTPRequestLogFilter(rctx)\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*HTTPRequestLogFilter)\n\tfc.Result = res\n\treturn ec.marshalOHttpRequestLogFilter2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestLogFilter(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query_activeProject(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Query().ActiveProject(rctx)\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*Project)\n\tfc.Result = res\n\treturn ec.marshalOProject2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProject(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query_projects(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Query().Projects(rctx)\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]Project)\n\tfc.Result = res\n\treturn ec.marshalNProject2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProjectᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query_scope(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Query().Scope(rctx)\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]ScopeRule)\n\tfc.Result = res\n\treturn ec.marshalNScopeRule2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRuleᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query_senderRequest(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Query_senderRequest_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Query().SenderRequest(rctx, args[\"id\"].(ulid.ULID))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*SenderRequest)\n\tfc.Result = res\n\treturn ec.marshalOSenderRequest2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequest(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query_senderRequests(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Query().SenderRequests(rctx)\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]SenderRequest)\n\tfc.Result = res\n\treturn ec.marshalNSenderRequest2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequestᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query_interceptedRequests(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Query().InterceptedRequests(rctx)\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]HTTPRequest)\n\tfc.Result = res\n\treturn ec.marshalNHttpRequest2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query_interceptedRequest(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: true,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Query_interceptedRequest_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.resolvers.Query().InterceptedRequest(rctx, args[\"id\"].(ulid.ULID))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*HTTPRequest)\n\tfc.Result = res\n\treturn ec.marshalOHttpRequest2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequest(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field_Query___type_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.introspectType(args[\"name\"].(string))\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*introspection.Type)\n\tfc.Result = res\n\treturn ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"Query\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn ec.introspectSchema()\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*introspection.Schema)\n\tfc.Result = res\n\treturn ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _ScopeHeader_key(ctx context.Context, field graphql.CollectedField, obj *ScopeHeader) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"ScopeHeader\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Key, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalORegexp2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _ScopeHeader_value(ctx context.Context, field graphql.CollectedField, obj *ScopeHeader) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"ScopeHeader\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Value, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalORegexp2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _ScopeRule_url(ctx context.Context, field graphql.CollectedField, obj *ScopeRule) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"ScopeRule\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.URL, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalORegexp2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _ScopeRule_header(ctx context.Context, field graphql.CollectedField, obj *ScopeRule) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"ScopeRule\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Header, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*ScopeHeader)\n\tfc.Result = res\n\treturn ec.marshalOScopeHeader2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeHeader(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _ScopeRule_body(ctx context.Context, field graphql.CollectedField, obj *ScopeRule) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"ScopeRule\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Body, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalORegexp2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _SenderRequest_id(ctx context.Context, field graphql.CollectedField, obj *SenderRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"SenderRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.ID, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(ulid.ULID)\n\tfc.Result = res\n\treturn ec.marshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _SenderRequest_sourceRequestLogID(ctx context.Context, field graphql.CollectedField, obj *SenderRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"SenderRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.SourceRequestLogID, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*ulid.ULID)\n\tfc.Result = res\n\treturn ec.marshalOID2ᚖgithubᚗcomᚋoklogᚋulidᚐULID(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _SenderRequest_url(ctx context.Context, field graphql.CollectedField, obj *SenderRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"SenderRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.URL, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*url.URL)\n\tfc.Result = res\n\treturn ec.marshalNURL2ᚖnetᚋurlᚐURL(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _SenderRequest_method(ctx context.Context, field graphql.CollectedField, obj *SenderRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"SenderRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Method, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(HTTPMethod)\n\tfc.Result = res\n\treturn ec.marshalNHttpMethod2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPMethod(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _SenderRequest_proto(ctx context.Context, field graphql.CollectedField, obj *SenderRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"SenderRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Proto, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(HTTPProtocol)\n\tfc.Result = res\n\treturn ec.marshalNHttpProtocol2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _SenderRequest_headers(ctx context.Context, field graphql.CollectedField, obj *SenderRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"SenderRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Headers, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]HTTPHeader)\n\tfc.Result = res\n\treturn ec.marshalOHttpHeader2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _SenderRequest_body(ctx context.Context, field graphql.CollectedField, obj *SenderRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"SenderRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Body, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _SenderRequest_timestamp(ctx context.Context, field graphql.CollectedField, obj *SenderRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"SenderRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Timestamp, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(time.Time)\n\tfc.Result = res\n\treturn ec.marshalNTime2timeᚐTime(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _SenderRequest_response(ctx context.Context, field graphql.CollectedField, obj *SenderRequest) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"SenderRequest\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Response, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*HTTPResponseLog)\n\tfc.Result = res\n\treturn ec.marshalOHttpResponseLog2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPResponseLog(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _SenderRequestFilter_onlyInScope(ctx context.Context, field graphql.CollectedField, obj *SenderRequestFilter) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"SenderRequestFilter\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.OnlyInScope, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) _SenderRequestFilter_searchExpression(ctx context.Context, field graphql.CollectedField, obj *SenderRequestFilter) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"SenderRequestFilter\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.SearchExpression, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Directive\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Name, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalNString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Directive_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Directive\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Description, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalOString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Directive\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Locations, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]string)\n\tfc.Result = res\n\treturn ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Directive\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Args, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]introspection.InputValue)\n\tfc.Result = res\n\treturn ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Directive\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.IsRepeatable, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__EnumValue\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Name, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalNString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___EnumValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__EnumValue\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Description, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalOString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__EnumValue\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.IsDeprecated(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__EnumValue\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.DeprecationReason(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Field_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Field\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Name, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalNString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Field_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Field\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Description, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalOString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Field_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Field\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Args, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]introspection.InputValue)\n\tfc.Result = res\n\treturn ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Field_type(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Field\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Type, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*introspection.Type)\n\tfc.Result = res\n\treturn ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Field\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.IsDeprecated(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(bool)\n\tfc.Result = res\n\treturn ec.marshalNBoolean2bool(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Field_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Field\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.DeprecationReason(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___InputValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__InputValue\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Name, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalNString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___InputValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__InputValue\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Description, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalOString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___InputValue_type(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__InputValue\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Type, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*introspection.Type)\n\tfc.Result = res\n\treturn ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__InputValue\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   false,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.DefaultValue, nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Schema\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Types(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]introspection.Type)\n\tfc.Result = res\n\treturn ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Schema_queryType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Schema\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.QueryType(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*introspection.Type)\n\tfc.Result = res\n\treturn ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Schema_mutationType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Schema\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.MutationType(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*introspection.Type)\n\tfc.Result = res\n\treturn ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Schema\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.SubscriptionType(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*introspection.Type)\n\tfc.Result = res\n\treturn ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Schema_directives(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Schema\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Directives(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]introspection.Directive)\n\tfc.Result = res\n\treturn ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Type\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Kind(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\tif !graphql.HasFieldError(ctx, fc) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalN__TypeKind2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Type_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Type\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Name(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*string)\n\tfc.Result = res\n\treturn ec.marshalOString2ᚖstring(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Type_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Type\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Description(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(string)\n\tfc.Result = res\n\treturn ec.marshalOString2string(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Type\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field___Type_fields_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Fields(args[\"includeDeprecated\"].(bool)), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]introspection.Field)\n\tfc.Result = res\n\treturn ec.marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Type\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.Interfaces(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]introspection.Type)\n\tfc.Result = res\n\treturn ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Type\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.PossibleTypes(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]introspection.Type)\n\tfc.Result = res\n\treturn ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Type\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\trawArgs := field.ArgumentMap(ec.Variables)\n\targs, err := ec.field___Type_enumValues_args(ctx, rawArgs)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tfc.Args = args\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.EnumValues(args[\"includeDeprecated\"].(bool)), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]introspection.EnumValue)\n\tfc.Result = res\n\treturn ec.marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Type_inputFields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Type\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.InputFields(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.([]introspection.InputValue)\n\tfc.Result = res\n\treturn ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res)\n}\n\nfunc (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = graphql.Null\n\t\t}\n\t}()\n\tfc := &graphql.FieldContext{\n\t\tObject:     \"__Type\",\n\t\tField:      field,\n\t\tArgs:       nil,\n\t\tIsMethod:   true,\n\t\tIsResolver: false,\n\t}\n\n\tctx = graphql.WithFieldContext(ctx, fc)\n\tresTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {\n\t\tctx = rctx // use context from middleware stack in children\n\t\treturn obj.OfType(), nil\n\t})\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn graphql.Null\n\t}\n\tif resTmp == nil {\n\t\treturn graphql.Null\n\t}\n\tres := resTmp.(*introspection.Type)\n\tfc.Result = res\n\treturn ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)\n}\n\n// endregion **************************** field.gotpl *****************************\n\n// region    **************************** input.gotpl *****************************\n\nfunc (ec *executionContext) unmarshalInputHttpHeaderInput(ctx context.Context, obj interface{}) (HTTPHeaderInput, error) {\n\tvar it HTTPHeaderInput\n\tasMap := map[string]interface{}{}\n\tfor k, v := range obj.(map[string]interface{}) {\n\t\tasMap[k] = v\n\t}\n\n\tfor k, v := range asMap {\n\t\tswitch k {\n\t\tcase \"key\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"key\"))\n\t\t\tit.Key, err = ec.unmarshalNString2string(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"value\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"value\"))\n\t\t\tit.Value, err = ec.unmarshalNString2string(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn it, nil\n}\n\nfunc (ec *executionContext) unmarshalInputHttpRequestLogFilterInput(ctx context.Context, obj interface{}) (HTTPRequestLogFilterInput, error) {\n\tvar it HTTPRequestLogFilterInput\n\tasMap := map[string]interface{}{}\n\tfor k, v := range obj.(map[string]interface{}) {\n\t\tasMap[k] = v\n\t}\n\n\tfor k, v := range asMap {\n\t\tswitch k {\n\t\tcase \"onlyInScope\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"onlyInScope\"))\n\t\t\tit.OnlyInScope, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"searchExpression\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"searchExpression\"))\n\t\t\tit.SearchExpression, err = ec.unmarshalOString2ᚖstring(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn it, nil\n}\n\nfunc (ec *executionContext) unmarshalInputModifyRequestInput(ctx context.Context, obj interface{}) (ModifyRequestInput, error) {\n\tvar it ModifyRequestInput\n\tasMap := map[string]interface{}{}\n\tfor k, v := range obj.(map[string]interface{}) {\n\t\tasMap[k] = v\n\t}\n\n\tfor k, v := range asMap {\n\t\tswitch k {\n\t\tcase \"id\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"id\"))\n\t\t\tit.ID, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"url\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"url\"))\n\t\t\tit.URL, err = ec.unmarshalNURL2ᚖnetᚋurlᚐURL(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"method\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"method\"))\n\t\t\tit.Method, err = ec.unmarshalNHttpMethod2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPMethod(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"proto\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"proto\"))\n\t\t\tit.Proto, err = ec.unmarshalNHttpProtocol2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"headers\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"headers\"))\n\t\t\tit.Headers, err = ec.unmarshalOHttpHeaderInput2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderInputᚄ(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"body\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"body\"))\n\t\t\tit.Body, err = ec.unmarshalOString2ᚖstring(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"modifyResponse\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"modifyResponse\"))\n\t\t\tit.ModifyResponse, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn it, nil\n}\n\nfunc (ec *executionContext) unmarshalInputModifyResponseInput(ctx context.Context, obj interface{}) (ModifyResponseInput, error) {\n\tvar it ModifyResponseInput\n\tasMap := map[string]interface{}{}\n\tfor k, v := range obj.(map[string]interface{}) {\n\t\tasMap[k] = v\n\t}\n\n\tfor k, v := range asMap {\n\t\tswitch k {\n\t\tcase \"requestID\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"requestID\"))\n\t\t\tit.RequestID, err = ec.unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"proto\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"proto\"))\n\t\t\tit.Proto, err = ec.unmarshalNHttpProtocol2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"headers\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"headers\"))\n\t\t\tit.Headers, err = ec.unmarshalOHttpHeaderInput2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderInputᚄ(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"body\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"body\"))\n\t\t\tit.Body, err = ec.unmarshalOString2ᚖstring(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"statusCode\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"statusCode\"))\n\t\t\tit.StatusCode, err = ec.unmarshalNInt2int(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"statusReason\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"statusReason\"))\n\t\t\tit.StatusReason, err = ec.unmarshalNString2string(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn it, nil\n}\n\nfunc (ec *executionContext) unmarshalInputScopeHeaderInput(ctx context.Context, obj interface{}) (ScopeHeaderInput, error) {\n\tvar it ScopeHeaderInput\n\tasMap := map[string]interface{}{}\n\tfor k, v := range obj.(map[string]interface{}) {\n\t\tasMap[k] = v\n\t}\n\n\tfor k, v := range asMap {\n\t\tswitch k {\n\t\tcase \"key\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"key\"))\n\t\t\tit.Key, err = ec.unmarshalORegexp2ᚖstring(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"value\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"value\"))\n\t\t\tit.Value, err = ec.unmarshalORegexp2ᚖstring(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn it, nil\n}\n\nfunc (ec *executionContext) unmarshalInputScopeRuleInput(ctx context.Context, obj interface{}) (ScopeRuleInput, error) {\n\tvar it ScopeRuleInput\n\tasMap := map[string]interface{}{}\n\tfor k, v := range obj.(map[string]interface{}) {\n\t\tasMap[k] = v\n\t}\n\n\tfor k, v := range asMap {\n\t\tswitch k {\n\t\tcase \"url\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"url\"))\n\t\t\tit.URL, err = ec.unmarshalORegexp2ᚖstring(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"header\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"header\"))\n\t\t\tit.Header, err = ec.unmarshalOScopeHeaderInput2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeHeaderInput(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"body\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"body\"))\n\t\t\tit.Body, err = ec.unmarshalORegexp2ᚖstring(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn it, nil\n}\n\nfunc (ec *executionContext) unmarshalInputSenderRequestFilterInput(ctx context.Context, obj interface{}) (SenderRequestFilterInput, error) {\n\tvar it SenderRequestFilterInput\n\tasMap := map[string]interface{}{}\n\tfor k, v := range obj.(map[string]interface{}) {\n\t\tasMap[k] = v\n\t}\n\n\tfor k, v := range asMap {\n\t\tswitch k {\n\t\tcase \"onlyInScope\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"onlyInScope\"))\n\t\t\tit.OnlyInScope, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"searchExpression\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"searchExpression\"))\n\t\t\tit.SearchExpression, err = ec.unmarshalOString2ᚖstring(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn it, nil\n}\n\nfunc (ec *executionContext) unmarshalInputSenderRequestInput(ctx context.Context, obj interface{}) (SenderRequestInput, error) {\n\tvar it SenderRequestInput\n\tasMap := map[string]interface{}{}\n\tfor k, v := range obj.(map[string]interface{}) {\n\t\tasMap[k] = v\n\t}\n\n\tfor k, v := range asMap {\n\t\tswitch k {\n\t\tcase \"id\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"id\"))\n\t\t\tit.ID, err = ec.unmarshalOID2ᚖgithubᚗcomᚋoklogᚋulidᚐULID(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"url\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"url\"))\n\t\t\tit.URL, err = ec.unmarshalNURL2ᚖnetᚋurlᚐURL(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"method\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"method\"))\n\t\t\tit.Method, err = ec.unmarshalOHttpMethod2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPMethod(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"proto\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"proto\"))\n\t\t\tit.Proto, err = ec.unmarshalOHttpProtocol2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"headers\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"headers\"))\n\t\t\tit.Headers, err = ec.unmarshalOHttpHeaderInput2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderInputᚄ(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"body\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"body\"))\n\t\t\tit.Body, err = ec.unmarshalOString2ᚖstring(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn it, nil\n}\n\nfunc (ec *executionContext) unmarshalInputUpdateInterceptSettingsInput(ctx context.Context, obj interface{}) (UpdateInterceptSettingsInput, error) {\n\tvar it UpdateInterceptSettingsInput\n\tasMap := map[string]interface{}{}\n\tfor k, v := range obj.(map[string]interface{}) {\n\t\tasMap[k] = v\n\t}\n\n\tfor k, v := range asMap {\n\t\tswitch k {\n\t\tcase \"requestsEnabled\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"requestsEnabled\"))\n\t\t\tit.RequestsEnabled, err = ec.unmarshalNBoolean2bool(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"responsesEnabled\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"responsesEnabled\"))\n\t\t\tit.ResponsesEnabled, err = ec.unmarshalNBoolean2bool(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"requestFilter\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"requestFilter\"))\n\t\t\tit.RequestFilter, err = ec.unmarshalOString2ᚖstring(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\tcase \"responseFilter\":\n\t\t\tvar err error\n\n\t\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithField(\"responseFilter\"))\n\t\t\tit.ResponseFilter, err = ec.unmarshalOString2ᚖstring(ctx, v)\n\t\t\tif err != nil {\n\t\t\t\treturn it, err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn it, nil\n}\n\n// endregion **************************** input.gotpl *****************************\n\n// region    ************************** interface.gotpl ***************************\n\n// endregion ************************** interface.gotpl ***************************\n\n// region    **************************** object.gotpl ****************************\n\nvar cancelRequestResultImplementors = []string{\"CancelRequestResult\"}\n\nfunc (ec *executionContext) _CancelRequestResult(ctx context.Context, sel ast.SelectionSet, obj *CancelRequestResult) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, cancelRequestResultImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"CancelRequestResult\")\n\t\tcase \"success\":\n\t\t\tout.Values[i] = ec._CancelRequestResult_success(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar cancelResponseResultImplementors = []string{\"CancelResponseResult\"}\n\nfunc (ec *executionContext) _CancelResponseResult(ctx context.Context, sel ast.SelectionSet, obj *CancelResponseResult) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, cancelResponseResultImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"CancelResponseResult\")\n\t\tcase \"success\":\n\t\t\tout.Values[i] = ec._CancelResponseResult_success(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar clearHTTPRequestLogResultImplementors = []string{\"ClearHTTPRequestLogResult\"}\n\nfunc (ec *executionContext) _ClearHTTPRequestLogResult(ctx context.Context, sel ast.SelectionSet, obj *ClearHTTPRequestLogResult) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, clearHTTPRequestLogResultImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"ClearHTTPRequestLogResult\")\n\t\tcase \"success\":\n\t\t\tout.Values[i] = ec._ClearHTTPRequestLogResult_success(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar closeProjectResultImplementors = []string{\"CloseProjectResult\"}\n\nfunc (ec *executionContext) _CloseProjectResult(ctx context.Context, sel ast.SelectionSet, obj *CloseProjectResult) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, closeProjectResultImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"CloseProjectResult\")\n\t\tcase \"success\":\n\t\t\tout.Values[i] = ec._CloseProjectResult_success(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar deleteProjectResultImplementors = []string{\"DeleteProjectResult\"}\n\nfunc (ec *executionContext) _DeleteProjectResult(ctx context.Context, sel ast.SelectionSet, obj *DeleteProjectResult) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, deleteProjectResultImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"DeleteProjectResult\")\n\t\tcase \"success\":\n\t\t\tout.Values[i] = ec._DeleteProjectResult_success(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar deleteSenderRequestsResultImplementors = []string{\"DeleteSenderRequestsResult\"}\n\nfunc (ec *executionContext) _DeleteSenderRequestsResult(ctx context.Context, sel ast.SelectionSet, obj *DeleteSenderRequestsResult) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, deleteSenderRequestsResultImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"DeleteSenderRequestsResult\")\n\t\tcase \"success\":\n\t\t\tout.Values[i] = ec._DeleteSenderRequestsResult_success(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar httpHeaderImplementors = []string{\"HttpHeader\"}\n\nfunc (ec *executionContext) _HttpHeader(ctx context.Context, sel ast.SelectionSet, obj *HTTPHeader) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, httpHeaderImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"HttpHeader\")\n\t\tcase \"key\":\n\t\t\tout.Values[i] = ec._HttpHeader_key(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"value\":\n\t\t\tout.Values[i] = ec._HttpHeader_value(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar httpRequestImplementors = []string{\"HttpRequest\"}\n\nfunc (ec *executionContext) _HttpRequest(ctx context.Context, sel ast.SelectionSet, obj *HTTPRequest) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, httpRequestImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"HttpRequest\")\n\t\tcase \"id\":\n\t\t\tout.Values[i] = ec._HttpRequest_id(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"url\":\n\t\t\tout.Values[i] = ec._HttpRequest_url(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"method\":\n\t\t\tout.Values[i] = ec._HttpRequest_method(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"proto\":\n\t\t\tout.Values[i] = ec._HttpRequest_proto(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"headers\":\n\t\t\tout.Values[i] = ec._HttpRequest_headers(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"body\":\n\t\t\tout.Values[i] = ec._HttpRequest_body(ctx, field, obj)\n\t\tcase \"response\":\n\t\t\tout.Values[i] = ec._HttpRequest_response(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar httpRequestLogImplementors = []string{\"HttpRequestLog\"}\n\nfunc (ec *executionContext) _HttpRequestLog(ctx context.Context, sel ast.SelectionSet, obj *HTTPRequestLog) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, httpRequestLogImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"HttpRequestLog\")\n\t\tcase \"id\":\n\t\t\tout.Values[i] = ec._HttpRequestLog_id(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"url\":\n\t\t\tout.Values[i] = ec._HttpRequestLog_url(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"method\":\n\t\t\tout.Values[i] = ec._HttpRequestLog_method(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"proto\":\n\t\t\tout.Values[i] = ec._HttpRequestLog_proto(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"headers\":\n\t\t\tout.Values[i] = ec._HttpRequestLog_headers(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"body\":\n\t\t\tout.Values[i] = ec._HttpRequestLog_body(ctx, field, obj)\n\t\tcase \"timestamp\":\n\t\t\tout.Values[i] = ec._HttpRequestLog_timestamp(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"response\":\n\t\t\tout.Values[i] = ec._HttpRequestLog_response(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar httpRequestLogFilterImplementors = []string{\"HttpRequestLogFilter\"}\n\nfunc (ec *executionContext) _HttpRequestLogFilter(ctx context.Context, sel ast.SelectionSet, obj *HTTPRequestLogFilter) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, httpRequestLogFilterImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"HttpRequestLogFilter\")\n\t\tcase \"onlyInScope\":\n\t\t\tout.Values[i] = ec._HttpRequestLogFilter_onlyInScope(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"searchExpression\":\n\t\t\tout.Values[i] = ec._HttpRequestLogFilter_searchExpression(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar httpResponseImplementors = []string{\"HttpResponse\"}\n\nfunc (ec *executionContext) _HttpResponse(ctx context.Context, sel ast.SelectionSet, obj *HTTPResponse) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, httpResponseImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"HttpResponse\")\n\t\tcase \"id\":\n\t\t\tout.Values[i] = ec._HttpResponse_id(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"proto\":\n\t\t\tout.Values[i] = ec._HttpResponse_proto(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"statusCode\":\n\t\t\tout.Values[i] = ec._HttpResponse_statusCode(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"statusReason\":\n\t\t\tout.Values[i] = ec._HttpResponse_statusReason(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"body\":\n\t\t\tout.Values[i] = ec._HttpResponse_body(ctx, field, obj)\n\t\tcase \"headers\":\n\t\t\tout.Values[i] = ec._HttpResponse_headers(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar httpResponseLogImplementors = []string{\"HttpResponseLog\"}\n\nfunc (ec *executionContext) _HttpResponseLog(ctx context.Context, sel ast.SelectionSet, obj *HTTPResponseLog) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, httpResponseLogImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"HttpResponseLog\")\n\t\tcase \"id\":\n\t\t\tout.Values[i] = ec._HttpResponseLog_id(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"proto\":\n\t\t\tout.Values[i] = ec._HttpResponseLog_proto(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"statusCode\":\n\t\t\tout.Values[i] = ec._HttpResponseLog_statusCode(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"statusReason\":\n\t\t\tout.Values[i] = ec._HttpResponseLog_statusReason(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"body\":\n\t\t\tout.Values[i] = ec._HttpResponseLog_body(ctx, field, obj)\n\t\tcase \"headers\":\n\t\t\tout.Values[i] = ec._HttpResponseLog_headers(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar interceptSettingsImplementors = []string{\"InterceptSettings\"}\n\nfunc (ec *executionContext) _InterceptSettings(ctx context.Context, sel ast.SelectionSet, obj *InterceptSettings) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, interceptSettingsImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"InterceptSettings\")\n\t\tcase \"requestsEnabled\":\n\t\t\tout.Values[i] = ec._InterceptSettings_requestsEnabled(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"responsesEnabled\":\n\t\t\tout.Values[i] = ec._InterceptSettings_responsesEnabled(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"requestFilter\":\n\t\t\tout.Values[i] = ec._InterceptSettings_requestFilter(ctx, field, obj)\n\t\tcase \"responseFilter\":\n\t\t\tout.Values[i] = ec._InterceptSettings_responseFilter(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar modifyRequestResultImplementors = []string{\"ModifyRequestResult\"}\n\nfunc (ec *executionContext) _ModifyRequestResult(ctx context.Context, sel ast.SelectionSet, obj *ModifyRequestResult) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, modifyRequestResultImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"ModifyRequestResult\")\n\t\tcase \"success\":\n\t\t\tout.Values[i] = ec._ModifyRequestResult_success(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar modifyResponseResultImplementors = []string{\"ModifyResponseResult\"}\n\nfunc (ec *executionContext) _ModifyResponseResult(ctx context.Context, sel ast.SelectionSet, obj *ModifyResponseResult) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, modifyResponseResultImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"ModifyResponseResult\")\n\t\tcase \"success\":\n\t\t\tout.Values[i] = ec._ModifyResponseResult_success(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar mutationImplementors = []string{\"Mutation\"}\n\nfunc (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, mutationImplementors)\n\n\tctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{\n\t\tObject: \"Mutation\",\n\t})\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"Mutation\")\n\t\tcase \"createProject\":\n\t\t\tout.Values[i] = ec._Mutation_createProject(ctx, field)\n\t\tcase \"openProject\":\n\t\t\tout.Values[i] = ec._Mutation_openProject(ctx, field)\n\t\tcase \"closeProject\":\n\t\t\tout.Values[i] = ec._Mutation_closeProject(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"deleteProject\":\n\t\t\tout.Values[i] = ec._Mutation_deleteProject(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"clearHTTPRequestLog\":\n\t\t\tout.Values[i] = ec._Mutation_clearHTTPRequestLog(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"setScope\":\n\t\t\tout.Values[i] = ec._Mutation_setScope(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"setHttpRequestLogFilter\":\n\t\t\tout.Values[i] = ec._Mutation_setHttpRequestLogFilter(ctx, field)\n\t\tcase \"setSenderRequestFilter\":\n\t\t\tout.Values[i] = ec._Mutation_setSenderRequestFilter(ctx, field)\n\t\tcase \"createOrUpdateSenderRequest\":\n\t\t\tout.Values[i] = ec._Mutation_createOrUpdateSenderRequest(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"createSenderRequestFromHttpRequestLog\":\n\t\t\tout.Values[i] = ec._Mutation_createSenderRequestFromHttpRequestLog(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"sendRequest\":\n\t\t\tout.Values[i] = ec._Mutation_sendRequest(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"deleteSenderRequests\":\n\t\t\tout.Values[i] = ec._Mutation_deleteSenderRequests(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"modifyRequest\":\n\t\t\tout.Values[i] = ec._Mutation_modifyRequest(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"cancelRequest\":\n\t\t\tout.Values[i] = ec._Mutation_cancelRequest(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"modifyResponse\":\n\t\t\tout.Values[i] = ec._Mutation_modifyResponse(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"cancelResponse\":\n\t\t\tout.Values[i] = ec._Mutation_cancelResponse(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"updateInterceptSettings\":\n\t\t\tout.Values[i] = ec._Mutation_updateInterceptSettings(ctx, field)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar projectImplementors = []string{\"Project\"}\n\nfunc (ec *executionContext) _Project(ctx context.Context, sel ast.SelectionSet, obj *Project) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, projectImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"Project\")\n\t\tcase \"id\":\n\t\t\tout.Values[i] = ec._Project_id(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"name\":\n\t\t\tout.Values[i] = ec._Project_name(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"isActive\":\n\t\t\tout.Values[i] = ec._Project_isActive(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"settings\":\n\t\t\tout.Values[i] = ec._Project_settings(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar projectSettingsImplementors = []string{\"ProjectSettings\"}\n\nfunc (ec *executionContext) _ProjectSettings(ctx context.Context, sel ast.SelectionSet, obj *ProjectSettings) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, projectSettingsImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"ProjectSettings\")\n\t\tcase \"intercept\":\n\t\t\tout.Values[i] = ec._ProjectSettings_intercept(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar queryImplementors = []string{\"Query\"}\n\nfunc (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors)\n\n\tctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{\n\t\tObject: \"Query\",\n\t})\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"Query\")\n\t\tcase \"httpRequestLog\":\n\t\t\tfield := field\n\t\t\tout.Concurrently(i, func() (res graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tres = ec._Query_httpRequestLog(ctx, field)\n\t\t\t\treturn res\n\t\t\t})\n\t\tcase \"httpRequestLogs\":\n\t\t\tfield := field\n\t\t\tout.Concurrently(i, func() (res graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tres = ec._Query_httpRequestLogs(ctx, field)\n\t\t\t\tif res == graphql.Null {\n\t\t\t\t\tatomic.AddUint32(&invalids, 1)\n\t\t\t\t}\n\t\t\t\treturn res\n\t\t\t})\n\t\tcase \"httpRequestLogFilter\":\n\t\t\tfield := field\n\t\t\tout.Concurrently(i, func() (res graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tres = ec._Query_httpRequestLogFilter(ctx, field)\n\t\t\t\treturn res\n\t\t\t})\n\t\tcase \"activeProject\":\n\t\t\tfield := field\n\t\t\tout.Concurrently(i, func() (res graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tres = ec._Query_activeProject(ctx, field)\n\t\t\t\treturn res\n\t\t\t})\n\t\tcase \"projects\":\n\t\t\tfield := field\n\t\t\tout.Concurrently(i, func() (res graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tres = ec._Query_projects(ctx, field)\n\t\t\t\tif res == graphql.Null {\n\t\t\t\t\tatomic.AddUint32(&invalids, 1)\n\t\t\t\t}\n\t\t\t\treturn res\n\t\t\t})\n\t\tcase \"scope\":\n\t\t\tfield := field\n\t\t\tout.Concurrently(i, func() (res graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tres = ec._Query_scope(ctx, field)\n\t\t\t\tif res == graphql.Null {\n\t\t\t\t\tatomic.AddUint32(&invalids, 1)\n\t\t\t\t}\n\t\t\t\treturn res\n\t\t\t})\n\t\tcase \"senderRequest\":\n\t\t\tfield := field\n\t\t\tout.Concurrently(i, func() (res graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tres = ec._Query_senderRequest(ctx, field)\n\t\t\t\treturn res\n\t\t\t})\n\t\tcase \"senderRequests\":\n\t\t\tfield := field\n\t\t\tout.Concurrently(i, func() (res graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tres = ec._Query_senderRequests(ctx, field)\n\t\t\t\tif res == graphql.Null {\n\t\t\t\t\tatomic.AddUint32(&invalids, 1)\n\t\t\t\t}\n\t\t\t\treturn res\n\t\t\t})\n\t\tcase \"interceptedRequests\":\n\t\t\tfield := field\n\t\t\tout.Concurrently(i, func() (res graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tres = ec._Query_interceptedRequests(ctx, field)\n\t\t\t\tif res == graphql.Null {\n\t\t\t\t\tatomic.AddUint32(&invalids, 1)\n\t\t\t\t}\n\t\t\t\treturn res\n\t\t\t})\n\t\tcase \"interceptedRequest\":\n\t\t\tfield := field\n\t\t\tout.Concurrently(i, func() (res graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tres = ec._Query_interceptedRequest(ctx, field)\n\t\t\t\treturn res\n\t\t\t})\n\t\tcase \"__type\":\n\t\t\tout.Values[i] = ec._Query___type(ctx, field)\n\t\tcase \"__schema\":\n\t\t\tout.Values[i] = ec._Query___schema(ctx, field)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar scopeHeaderImplementors = []string{\"ScopeHeader\"}\n\nfunc (ec *executionContext) _ScopeHeader(ctx context.Context, sel ast.SelectionSet, obj *ScopeHeader) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, scopeHeaderImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"ScopeHeader\")\n\t\tcase \"key\":\n\t\t\tout.Values[i] = ec._ScopeHeader_key(ctx, field, obj)\n\t\tcase \"value\":\n\t\t\tout.Values[i] = ec._ScopeHeader_value(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar scopeRuleImplementors = []string{\"ScopeRule\"}\n\nfunc (ec *executionContext) _ScopeRule(ctx context.Context, sel ast.SelectionSet, obj *ScopeRule) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, scopeRuleImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"ScopeRule\")\n\t\tcase \"url\":\n\t\t\tout.Values[i] = ec._ScopeRule_url(ctx, field, obj)\n\t\tcase \"header\":\n\t\t\tout.Values[i] = ec._ScopeRule_header(ctx, field, obj)\n\t\tcase \"body\":\n\t\t\tout.Values[i] = ec._ScopeRule_body(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar senderRequestImplementors = []string{\"SenderRequest\"}\n\nfunc (ec *executionContext) _SenderRequest(ctx context.Context, sel ast.SelectionSet, obj *SenderRequest) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, senderRequestImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"SenderRequest\")\n\t\tcase \"id\":\n\t\t\tout.Values[i] = ec._SenderRequest_id(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"sourceRequestLogID\":\n\t\t\tout.Values[i] = ec._SenderRequest_sourceRequestLogID(ctx, field, obj)\n\t\tcase \"url\":\n\t\t\tout.Values[i] = ec._SenderRequest_url(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"method\":\n\t\t\tout.Values[i] = ec._SenderRequest_method(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"proto\":\n\t\t\tout.Values[i] = ec._SenderRequest_proto(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"headers\":\n\t\t\tout.Values[i] = ec._SenderRequest_headers(ctx, field, obj)\n\t\tcase \"body\":\n\t\t\tout.Values[i] = ec._SenderRequest_body(ctx, field, obj)\n\t\tcase \"timestamp\":\n\t\t\tout.Values[i] = ec._SenderRequest_timestamp(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"response\":\n\t\t\tout.Values[i] = ec._SenderRequest_response(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar senderRequestFilterImplementors = []string{\"SenderRequestFilter\"}\n\nfunc (ec *executionContext) _SenderRequestFilter(ctx context.Context, sel ast.SelectionSet, obj *SenderRequestFilter) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, senderRequestFilterImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"SenderRequestFilter\")\n\t\tcase \"onlyInScope\":\n\t\t\tout.Values[i] = ec._SenderRequestFilter_onlyInScope(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"searchExpression\":\n\t\t\tout.Values[i] = ec._SenderRequestFilter_searchExpression(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar __DirectiveImplementors = []string{\"__Directive\"}\n\nfunc (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"__Directive\")\n\t\tcase \"name\":\n\t\t\tout.Values[i] = ec.___Directive_name(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"description\":\n\t\t\tout.Values[i] = ec.___Directive_description(ctx, field, obj)\n\t\tcase \"locations\":\n\t\t\tout.Values[i] = ec.___Directive_locations(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"args\":\n\t\t\tout.Values[i] = ec.___Directive_args(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"isRepeatable\":\n\t\t\tout.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar __EnumValueImplementors = []string{\"__EnumValue\"}\n\nfunc (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"__EnumValue\")\n\t\tcase \"name\":\n\t\t\tout.Values[i] = ec.___EnumValue_name(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"description\":\n\t\t\tout.Values[i] = ec.___EnumValue_description(ctx, field, obj)\n\t\tcase \"isDeprecated\":\n\t\t\tout.Values[i] = ec.___EnumValue_isDeprecated(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"deprecationReason\":\n\t\t\tout.Values[i] = ec.___EnumValue_deprecationReason(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar __FieldImplementors = []string{\"__Field\"}\n\nfunc (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"__Field\")\n\t\tcase \"name\":\n\t\t\tout.Values[i] = ec.___Field_name(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"description\":\n\t\t\tout.Values[i] = ec.___Field_description(ctx, field, obj)\n\t\tcase \"args\":\n\t\t\tout.Values[i] = ec.___Field_args(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"type\":\n\t\t\tout.Values[i] = ec.___Field_type(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"isDeprecated\":\n\t\t\tout.Values[i] = ec.___Field_isDeprecated(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"deprecationReason\":\n\t\t\tout.Values[i] = ec.___Field_deprecationReason(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar __InputValueImplementors = []string{\"__InputValue\"}\n\nfunc (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"__InputValue\")\n\t\tcase \"name\":\n\t\t\tout.Values[i] = ec.___InputValue_name(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"description\":\n\t\t\tout.Values[i] = ec.___InputValue_description(ctx, field, obj)\n\t\tcase \"type\":\n\t\t\tout.Values[i] = ec.___InputValue_type(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"defaultValue\":\n\t\t\tout.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar __SchemaImplementors = []string{\"__Schema\"}\n\nfunc (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"__Schema\")\n\t\tcase \"types\":\n\t\t\tout.Values[i] = ec.___Schema_types(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"queryType\":\n\t\t\tout.Values[i] = ec.___Schema_queryType(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"mutationType\":\n\t\t\tout.Values[i] = ec.___Schema_mutationType(ctx, field, obj)\n\t\tcase \"subscriptionType\":\n\t\t\tout.Values[i] = ec.___Schema_subscriptionType(ctx, field, obj)\n\t\tcase \"directives\":\n\t\t\tout.Values[i] = ec.___Schema_directives(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\nvar __TypeImplementors = []string{\"__Type\"}\n\nfunc (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler {\n\tfields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors)\n\n\tout := graphql.NewFieldSet(fields)\n\tvar invalids uint32\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString(\"__Type\")\n\t\tcase \"kind\":\n\t\t\tout.Values[i] = ec.___Type_kind(ctx, field, obj)\n\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\tinvalids++\n\t\t\t}\n\t\tcase \"name\":\n\t\t\tout.Values[i] = ec.___Type_name(ctx, field, obj)\n\t\tcase \"description\":\n\t\t\tout.Values[i] = ec.___Type_description(ctx, field, obj)\n\t\tcase \"fields\":\n\t\t\tout.Values[i] = ec.___Type_fields(ctx, field, obj)\n\t\tcase \"interfaces\":\n\t\t\tout.Values[i] = ec.___Type_interfaces(ctx, field, obj)\n\t\tcase \"possibleTypes\":\n\t\t\tout.Values[i] = ec.___Type_possibleTypes(ctx, field, obj)\n\t\tcase \"enumValues\":\n\t\t\tout.Values[i] = ec.___Type_enumValues(ctx, field, obj)\n\t\tcase \"inputFields\":\n\t\t\tout.Values[i] = ec.___Type_inputFields(ctx, field, obj)\n\t\tcase \"ofType\":\n\t\t\tout.Values[i] = ec.___Type_ofType(ctx, field, obj)\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalids > 0 {\n\t\treturn graphql.Null\n\t}\n\treturn out\n}\n\n// endregion **************************** object.gotpl ****************************\n\n// region    ***************************** type.gotpl *****************************\n\nfunc (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) {\n\tres, err := graphql.UnmarshalBoolean(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler {\n\tres := graphql.MarshalBoolean(v)\n\tif res == graphql.Null {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t}\n\treturn res\n}\n\nfunc (ec *executionContext) marshalNCancelRequestResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelRequestResult(ctx context.Context, sel ast.SelectionSet, v CancelRequestResult) graphql.Marshaler {\n\treturn ec._CancelRequestResult(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNCancelRequestResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelRequestResult(ctx context.Context, sel ast.SelectionSet, v *CancelRequestResult) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec._CancelRequestResult(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalNCancelResponseResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelResponseResult(ctx context.Context, sel ast.SelectionSet, v CancelResponseResult) graphql.Marshaler {\n\treturn ec._CancelResponseResult(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNCancelResponseResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelResponseResult(ctx context.Context, sel ast.SelectionSet, v *CancelResponseResult) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec._CancelResponseResult(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalNClearHTTPRequestLogResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐClearHTTPRequestLogResult(ctx context.Context, sel ast.SelectionSet, v ClearHTTPRequestLogResult) graphql.Marshaler {\n\treturn ec._ClearHTTPRequestLogResult(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNClearHTTPRequestLogResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐClearHTTPRequestLogResult(ctx context.Context, sel ast.SelectionSet, v *ClearHTTPRequestLogResult) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec._ClearHTTPRequestLogResult(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalNCloseProjectResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCloseProjectResult(ctx context.Context, sel ast.SelectionSet, v CloseProjectResult) graphql.Marshaler {\n\treturn ec._CloseProjectResult(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNCloseProjectResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCloseProjectResult(ctx context.Context, sel ast.SelectionSet, v *CloseProjectResult) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec._CloseProjectResult(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalNDeleteProjectResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐDeleteProjectResult(ctx context.Context, sel ast.SelectionSet, v DeleteProjectResult) graphql.Marshaler {\n\treturn ec._DeleteProjectResult(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNDeleteProjectResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐDeleteProjectResult(ctx context.Context, sel ast.SelectionSet, v *DeleteProjectResult) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec._DeleteProjectResult(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalNDeleteSenderRequestsResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐDeleteSenderRequestsResult(ctx context.Context, sel ast.SelectionSet, v DeleteSenderRequestsResult) graphql.Marshaler {\n\treturn ec._DeleteSenderRequestsResult(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNDeleteSenderRequestsResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐDeleteSenderRequestsResult(ctx context.Context, sel ast.SelectionSet, v *DeleteSenderRequestsResult) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec._DeleteSenderRequestsResult(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalNHttpHeader2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeader(ctx context.Context, sel ast.SelectionSet, v HTTPHeader) graphql.Marshaler {\n\treturn ec._HttpHeader(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNHttpHeader2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderᚄ(ctx context.Context, sel ast.SelectionSet, v []HTTPHeader) graphql.Marshaler {\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalNHttpHeader2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeader(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) unmarshalNHttpHeaderInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderInput(ctx context.Context, v interface{}) (HTTPHeaderInput, error) {\n\tres, err := ec.unmarshalInputHttpHeaderInput(ctx, v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) unmarshalNHttpMethod2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPMethod(ctx context.Context, v interface{}) (HTTPMethod, error) {\n\tvar res HTTPMethod\n\terr := res.UnmarshalGQL(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalNHttpMethod2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPMethod(ctx context.Context, sel ast.SelectionSet, v HTTPMethod) graphql.Marshaler {\n\treturn v\n}\n\nfunc (ec *executionContext) unmarshalNHttpProtocol2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx context.Context, v interface{}) (HTTPProtocol, error) {\n\tvar res HTTPProtocol\n\terr := res.UnmarshalGQL(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalNHttpProtocol2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx context.Context, sel ast.SelectionSet, v HTTPProtocol) graphql.Marshaler {\n\treturn v\n}\n\nfunc (ec *executionContext) marshalNHttpRequest2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequest(ctx context.Context, sel ast.SelectionSet, v HTTPRequest) graphql.Marshaler {\n\treturn ec._HttpRequest(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNHttpRequest2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestᚄ(ctx context.Context, sel ast.SelectionSet, v []HTTPRequest) graphql.Marshaler {\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalNHttpRequest2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequest(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) marshalNHttpRequestLog2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestLog(ctx context.Context, sel ast.SelectionSet, v HTTPRequestLog) graphql.Marshaler {\n\treturn ec._HttpRequestLog(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNHttpRequestLog2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestLogᚄ(ctx context.Context, sel ast.SelectionSet, v []HTTPRequestLog) graphql.Marshaler {\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalNHttpRequestLog2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestLog(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) unmarshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx context.Context, v interface{}) (ulid.ULID, error) {\n\tres, err := UnmarshalULID(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalNID2githubᚗcomᚋoklogᚋulidᚐULID(ctx context.Context, sel ast.SelectionSet, v ulid.ULID) graphql.Marshaler {\n\tres := MarshalULID(v)\n\tif res == graphql.Null {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t}\n\treturn res\n}\n\nfunc (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) {\n\tres, err := graphql.UnmarshalInt(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler {\n\tres := graphql.MarshalInt(v)\n\tif res == graphql.Null {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t}\n\treturn res\n}\n\nfunc (ec *executionContext) marshalNInterceptSettings2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx context.Context, sel ast.SelectionSet, v InterceptSettings) graphql.Marshaler {\n\treturn ec._InterceptSettings(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNInterceptSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx context.Context, sel ast.SelectionSet, v *InterceptSettings) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec._InterceptSettings(ctx, sel, v)\n}\n\nfunc (ec *executionContext) unmarshalNModifyRequestInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyRequestInput(ctx context.Context, v interface{}) (ModifyRequestInput, error) {\n\tres, err := ec.unmarshalInputModifyRequestInput(ctx, v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalNModifyRequestResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyRequestResult(ctx context.Context, sel ast.SelectionSet, v ModifyRequestResult) graphql.Marshaler {\n\treturn ec._ModifyRequestResult(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNModifyRequestResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyRequestResult(ctx context.Context, sel ast.SelectionSet, v *ModifyRequestResult) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec._ModifyRequestResult(ctx, sel, v)\n}\n\nfunc (ec *executionContext) unmarshalNModifyResponseInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyResponseInput(ctx context.Context, v interface{}) (ModifyResponseInput, error) {\n\tres, err := ec.unmarshalInputModifyResponseInput(ctx, v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalNModifyResponseResult2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyResponseResult(ctx context.Context, sel ast.SelectionSet, v ModifyResponseResult) graphql.Marshaler {\n\treturn ec._ModifyResponseResult(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNModifyResponseResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyResponseResult(ctx context.Context, sel ast.SelectionSet, v *ModifyResponseResult) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec._ModifyResponseResult(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalNProject2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProject(ctx context.Context, sel ast.SelectionSet, v Project) graphql.Marshaler {\n\treturn ec._Project(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNProject2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProjectᚄ(ctx context.Context, sel ast.SelectionSet, v []Project) graphql.Marshaler {\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalNProject2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProject(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) marshalNProjectSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProjectSettings(ctx context.Context, sel ast.SelectionSet, v *ProjectSettings) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec._ProjectSettings(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalNScopeRule2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRule(ctx context.Context, sel ast.SelectionSet, v ScopeRule) graphql.Marshaler {\n\treturn ec._ScopeRule(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNScopeRule2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRuleᚄ(ctx context.Context, sel ast.SelectionSet, v []ScopeRule) graphql.Marshaler {\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalNScopeRule2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRule(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) unmarshalNScopeRuleInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRuleInput(ctx context.Context, v interface{}) (ScopeRuleInput, error) {\n\tres, err := ec.unmarshalInputScopeRuleInput(ctx, v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) unmarshalNScopeRuleInput2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRuleInputᚄ(ctx context.Context, v interface{}) ([]ScopeRuleInput, error) {\n\tvar vSlice []interface{}\n\tif v != nil {\n\t\tif tmp1, ok := v.([]interface{}); ok {\n\t\t\tvSlice = tmp1\n\t\t} else {\n\t\t\tvSlice = []interface{}{v}\n\t\t}\n\t}\n\tvar err error\n\tres := make([]ScopeRuleInput, len(vSlice))\n\tfor i := range vSlice {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))\n\t\tres[i], err = ec.unmarshalNScopeRuleInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRuleInput(ctx, vSlice[i])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn res, nil\n}\n\nfunc (ec *executionContext) marshalNSenderRequest2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequest(ctx context.Context, sel ast.SelectionSet, v SenderRequest) graphql.Marshaler {\n\treturn ec._SenderRequest(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalNSenderRequest2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequestᚄ(ctx context.Context, sel ast.SelectionSet, v []SenderRequest) graphql.Marshaler {\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalNSenderRequest2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequest(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) marshalNSenderRequest2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequest(ctx context.Context, sel ast.SelectionSet, v *SenderRequest) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec._SenderRequest(ctx, sel, v)\n}\n\nfunc (ec *executionContext) unmarshalNSenderRequestInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequestInput(ctx context.Context, v interface{}) (SenderRequestInput, error) {\n\tres, err := ec.unmarshalInputSenderRequestInput(ctx, v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) {\n\tres, err := graphql.UnmarshalString(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler {\n\tres := graphql.MarshalString(v)\n\tif res == graphql.Null {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t}\n\treturn res\n}\n\nfunc (ec *executionContext) unmarshalNTime2timeᚐTime(ctx context.Context, v interface{}) (time.Time, error) {\n\tres, err := graphql.UnmarshalTime(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalNTime2timeᚐTime(ctx context.Context, sel ast.SelectionSet, v time.Time) graphql.Marshaler {\n\tres := graphql.MarshalTime(v)\n\tif res == graphql.Null {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t}\n\treturn res\n}\n\nfunc (ec *executionContext) unmarshalNURL2ᚖnetᚋurlᚐURL(ctx context.Context, v interface{}) (*url.URL, error) {\n\tres, err := UnmarshalURL(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalNURL2ᚖnetᚋurlᚐURL(ctx context.Context, sel ast.SelectionSet, v *url.URL) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\tres := MarshalURL(v)\n\tif res == graphql.Null {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t}\n\treturn res\n}\n\nfunc (ec *executionContext) unmarshalNUpdateInterceptSettingsInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐUpdateInterceptSettingsInput(ctx context.Context, v interface{}) (UpdateInterceptSettingsInput, error) {\n\tres, err := ec.unmarshalInputUpdateInterceptSettingsInput(ctx, v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler {\n\treturn ec.___Directive(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Directive) graphql.Marshaler {\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) {\n\tres, err := graphql.UnmarshalString(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler {\n\tres := graphql.MarshalString(v)\n\tif res == graphql.Null {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t}\n\treturn res\n}\n\nfunc (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) {\n\tvar vSlice []interface{}\n\tif v != nil {\n\t\tif tmp1, ok := v.([]interface{}); ok {\n\t\t\tvSlice = tmp1\n\t\t} else {\n\t\t\tvSlice = []interface{}{v}\n\t\t}\n\t}\n\tvar err error\n\tres := make([]string, len(vSlice))\n\tfor i := range vSlice {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))\n\t\tres[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn res, nil\n}\n\nfunc (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler {\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalN__DirectiveLocation2string(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx context.Context, sel ast.SelectionSet, v introspection.EnumValue) graphql.Marshaler {\n\treturn ec.___EnumValue(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx context.Context, sel ast.SelectionSet, v introspection.Field) graphql.Marshaler {\n\treturn ec.___Field(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx context.Context, sel ast.SelectionSet, v introspection.InputValue) graphql.Marshaler {\n\treturn ec.___InputValue(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler {\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v introspection.Type) graphql.Marshaler {\n\treturn ec.___Type(ctx, sel, &v)\n}\n\nfunc (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler {\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler {\n\tif v == nil {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t\treturn graphql.Null\n\t}\n\treturn ec.___Type(ctx, sel, v)\n}\n\nfunc (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) {\n\tres, err := graphql.UnmarshalString(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler {\n\tres := graphql.MarshalString(v)\n\tif res == graphql.Null {\n\t\tif !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {\n\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t}\n\t}\n\treturn res\n}\n\nfunc (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) {\n\tres, err := graphql.UnmarshalBoolean(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler {\n\treturn graphql.MarshalBoolean(v)\n}\n\nfunc (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) {\n\tif v == nil {\n\t\treturn nil, nil\n\t}\n\tres, err := graphql.UnmarshalBoolean(v)\n\treturn &res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn graphql.MarshalBoolean(*v)\n}\n\nfunc (ec *executionContext) marshalOHttpHeader2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderᚄ(ctx context.Context, sel ast.SelectionSet, v []HTTPHeader) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalNHttpHeader2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeader(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) unmarshalOHttpHeaderInput2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderInputᚄ(ctx context.Context, v interface{}) ([]HTTPHeaderInput, error) {\n\tif v == nil {\n\t\treturn nil, nil\n\t}\n\tvar vSlice []interface{}\n\tif v != nil {\n\t\tif tmp1, ok := v.([]interface{}); ok {\n\t\t\tvSlice = tmp1\n\t\t} else {\n\t\t\tvSlice = []interface{}{v}\n\t\t}\n\t}\n\tvar err error\n\tres := make([]HTTPHeaderInput, len(vSlice))\n\tfor i := range vSlice {\n\t\tctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))\n\t\tres[i], err = ec.unmarshalNHttpHeaderInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderInput(ctx, vSlice[i])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn res, nil\n}\n\nfunc (ec *executionContext) unmarshalOHttpMethod2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPMethod(ctx context.Context, v interface{}) (*HTTPMethod, error) {\n\tif v == nil {\n\t\treturn nil, nil\n\t}\n\tvar res = new(HTTPMethod)\n\terr := res.UnmarshalGQL(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalOHttpMethod2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPMethod(ctx context.Context, sel ast.SelectionSet, v *HTTPMethod) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn v\n}\n\nfunc (ec *executionContext) unmarshalOHttpProtocol2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx context.Context, v interface{}) (*HTTPProtocol, error) {\n\tif v == nil {\n\t\treturn nil, nil\n\t}\n\tvar res = new(HTTPProtocol)\n\terr := res.UnmarshalGQL(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalOHttpProtocol2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPProtocol(ctx context.Context, sel ast.SelectionSet, v *HTTPProtocol) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn v\n}\n\nfunc (ec *executionContext) marshalOHttpRequest2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequest(ctx context.Context, sel ast.SelectionSet, v *HTTPRequest) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn ec._HttpRequest(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalOHttpRequestLog2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestLog(ctx context.Context, sel ast.SelectionSet, v *HTTPRequestLog) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn ec._HttpRequestLog(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalOHttpRequestLogFilter2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestLogFilter(ctx context.Context, sel ast.SelectionSet, v *HTTPRequestLogFilter) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn ec._HttpRequestLogFilter(ctx, sel, v)\n}\n\nfunc (ec *executionContext) unmarshalOHttpRequestLogFilterInput2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPRequestLogFilterInput(ctx context.Context, v interface{}) (*HTTPRequestLogFilterInput, error) {\n\tif v == nil {\n\t\treturn nil, nil\n\t}\n\tres, err := ec.unmarshalInputHttpRequestLogFilterInput(ctx, v)\n\treturn &res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalOHttpResponse2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPResponse(ctx context.Context, sel ast.SelectionSet, v *HTTPResponse) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn ec._HttpResponse(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalOHttpResponseLog2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPResponseLog(ctx context.Context, sel ast.SelectionSet, v *HTTPResponseLog) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn ec._HttpResponseLog(ctx, sel, v)\n}\n\nfunc (ec *executionContext) unmarshalOID2ᚖgithubᚗcomᚋoklogᚋulidᚐULID(ctx context.Context, v interface{}) (*ulid.ULID, error) {\n\tif v == nil {\n\t\treturn nil, nil\n\t}\n\tres, err := UnmarshalULID(v)\n\treturn &res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalOID2ᚖgithubᚗcomᚋoklogᚋulidᚐULID(ctx context.Context, sel ast.SelectionSet, v *ulid.ULID) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn MarshalULID(*v)\n}\n\nfunc (ec *executionContext) marshalOProject2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProject(ctx context.Context, sel ast.SelectionSet, v *Project) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn ec._Project(ctx, sel, v)\n}\n\nfunc (ec *executionContext) unmarshalORegexp2ᚖstring(ctx context.Context, v interface{}) (*string, error) {\n\tif v == nil {\n\t\treturn nil, nil\n\t}\n\tres, err := graphql.UnmarshalString(v)\n\treturn &res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalORegexp2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn graphql.MarshalString(*v)\n}\n\nfunc (ec *executionContext) marshalOScopeHeader2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeHeader(ctx context.Context, sel ast.SelectionSet, v *ScopeHeader) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn ec._ScopeHeader(ctx, sel, v)\n}\n\nfunc (ec *executionContext) unmarshalOScopeHeaderInput2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeHeaderInput(ctx context.Context, v interface{}) (*ScopeHeaderInput, error) {\n\tif v == nil {\n\t\treturn nil, nil\n\t}\n\tres, err := ec.unmarshalInputScopeHeaderInput(ctx, v)\n\treturn &res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalOSenderRequest2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequest(ctx context.Context, sel ast.SelectionSet, v *SenderRequest) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn ec._SenderRequest(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalOSenderRequestFilter2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequestFilter(ctx context.Context, sel ast.SelectionSet, v *SenderRequestFilter) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn ec._SenderRequestFilter(ctx, sel, v)\n}\n\nfunc (ec *executionContext) unmarshalOSenderRequestFilterInput2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐSenderRequestFilterInput(ctx context.Context, v interface{}) (*SenderRequestFilterInput, error) {\n\tif v == nil {\n\t\treturn nil, nil\n\t}\n\tres, err := ec.unmarshalInputSenderRequestFilterInput(ctx, v)\n\treturn &res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) {\n\tres, err := graphql.UnmarshalString(v)\n\treturn res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalOString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler {\n\treturn graphql.MarshalString(v)\n}\n\nfunc (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) {\n\tif v == nil {\n\t\treturn nil, nil\n\t}\n\tres, err := graphql.UnmarshalString(v)\n\treturn &res, graphql.ErrorOnPath(ctx, err)\n}\n\nfunc (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn graphql.MarshalString(*v)\n}\n\nfunc (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Field) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v *introspection.Schema) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn ec.___Schema(ctx, sel, v)\n}\n\nfunc (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\tret := make(graphql.Array, len(v))\n\tvar wg sync.WaitGroup\n\tisLen1 := len(v) == 1\n\tif !isLen1 {\n\t\twg.Add(len(v))\n\t}\n\tfor i := range v {\n\t\ti := i\n\t\tfc := &graphql.FieldContext{\n\t\t\tIndex:  &i,\n\t\t\tResult: &v[i],\n\t\t}\n\t\tctx := graphql.WithFieldContext(ctx, fc)\n\t\tf := func(i int) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\t\t\tret = nil\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif !isLen1 {\n\t\t\t\tdefer wg.Done()\n\t\t\t}\n\t\t\tret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i])\n\t\t}\n\t\tif isLen1 {\n\t\t\tf(i)\n\t\t} else {\n\t\t\tgo f(i)\n\t\t}\n\n\t}\n\twg.Wait()\n\n\tfor _, e := range ret {\n\t\tif e == graphql.Null {\n\t\t\treturn graphql.Null\n\t\t}\n\t}\n\n\treturn ret\n}\n\nfunc (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler {\n\tif v == nil {\n\t\treturn graphql.Null\n\t}\n\treturn ec.___Type(ctx, sel, v)\n}\n\n// endregion ***************************** type.gotpl *****************************\n"
  },
  {
    "path": "pkg/api/http.go",
    "content": "package api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/99designs/gqlgen/graphql/handler\"\n\t\"github.com/99designs/gqlgen/graphql/playground\"\n\t\"github.com/gorilla/mux\"\n)\n\nfunc HTTPHandler(resolver *Resolver, gqlEndpoint string) http.Handler {\n\trouter := mux.NewRouter().SkipClean(true)\n\trouter.Methods(\"POST\").Handler(\n\t\thandler.NewDefaultServer(NewExecutableSchema(Config{\n\t\t\tResolvers: resolver,\n\t\t})),\n\t)\n\trouter.Methods(\"GET\").Handler(playground.Handler(\"GraphQL Playground\", gqlEndpoint))\n\n\treturn router\n}\n"
  },
  {
    "path": "pkg/api/models.go",
    "content": "package api\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"strconv\"\n\n\t\"github.com/99designs/gqlgen/graphql\"\n\t\"github.com/oklog/ulid\"\n)\n\nfunc MarshalULID(u ulid.ULID) graphql.Marshaler {\n\treturn graphql.WriterFunc(func(w io.Writer) {\n\t\tfmt.Fprint(w, strconv.Quote(u.String()))\n\t})\n}\n\nfunc UnmarshalULID(v interface{}) (ulid.ULID, error) {\n\trawULID, ok := v.(string)\n\tif !ok {\n\t\treturn ulid.ULID{}, fmt.Errorf(\"ulid must be a string\")\n\t}\n\n\tu, err := ulid.Parse(rawULID)\n\tif err != nil {\n\t\treturn ulid.ULID{}, fmt.Errorf(\"failed to parse ULID: %w\", err)\n\t}\n\n\treturn u, nil\n}\n\nfunc MarshalURL(u *url.URL) graphql.Marshaler {\n\treturn graphql.WriterFunc(func(w io.Writer) {\n\t\tfmt.Fprint(w, strconv.Quote(u.String()))\n\t})\n}\n\nfunc UnmarshalURL(v interface{}) (*url.URL, error) {\n\trawURL, ok := v.(string)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"url must be a string\")\n\t}\n\n\tu, err := url.Parse(rawURL)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse URL: %w\", err)\n\t}\n\n\treturn u, nil\n}\n\ntype HTTPHeaders []HTTPHeader\n\nfunc (h HTTPHeaders) Len() int {\n\treturn len(h)\n}\n\nfunc (h HTTPHeaders) Less(i, j int) bool {\n\treturn h[i].Key < h[j].Key\n}\n\nfunc (h HTTPHeaders) Swap(i, j int) {\n\th[i], h[j] = h[j], h[i]\n}\n"
  },
  {
    "path": "pkg/api/models_gen.go",
    "content": "// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/oklog/ulid\"\n)\n\ntype CancelRequestResult struct {\n\tSuccess bool `json:\"success\"`\n}\n\ntype CancelResponseResult struct {\n\tSuccess bool `json:\"success\"`\n}\n\ntype ClearHTTPRequestLogResult struct {\n\tSuccess bool `json:\"success\"`\n}\n\ntype CloseProjectResult struct {\n\tSuccess bool `json:\"success\"`\n}\n\ntype DeleteProjectResult struct {\n\tSuccess bool `json:\"success\"`\n}\n\ntype DeleteSenderRequestsResult struct {\n\tSuccess bool `json:\"success\"`\n}\n\ntype HTTPHeader struct {\n\tKey   string `json:\"key\"`\n\tValue string `json:\"value\"`\n}\n\ntype HTTPHeaderInput struct {\n\tKey   string `json:\"key\"`\n\tValue string `json:\"value\"`\n}\n\ntype HTTPRequest struct {\n\tID       ulid.ULID     `json:\"id\"`\n\tURL      *url.URL      `json:\"url\"`\n\tMethod   HTTPMethod    `json:\"method\"`\n\tProto    HTTPProtocol  `json:\"proto\"`\n\tHeaders  []HTTPHeader  `json:\"headers\"`\n\tBody     *string       `json:\"body\"`\n\tResponse *HTTPResponse `json:\"response\"`\n}\n\ntype HTTPRequestLog struct {\n\tID        ulid.ULID        `json:\"id\"`\n\tURL       string           `json:\"url\"`\n\tMethod    HTTPMethod       `json:\"method\"`\n\tProto     string           `json:\"proto\"`\n\tHeaders   []HTTPHeader     `json:\"headers\"`\n\tBody      *string          `json:\"body\"`\n\tTimestamp time.Time        `json:\"timestamp\"`\n\tResponse  *HTTPResponseLog `json:\"response\"`\n}\n\ntype HTTPRequestLogFilter struct {\n\tOnlyInScope      bool    `json:\"onlyInScope\"`\n\tSearchExpression *string `json:\"searchExpression\"`\n}\n\ntype HTTPRequestLogFilterInput struct {\n\tOnlyInScope      *bool   `json:\"onlyInScope\"`\n\tSearchExpression *string `json:\"searchExpression\"`\n}\n\ntype HTTPResponse struct {\n\t// Will be the same ID as its related request ID.\n\tID           ulid.ULID    `json:\"id\"`\n\tProto        HTTPProtocol `json:\"proto\"`\n\tStatusCode   int          `json:\"statusCode\"`\n\tStatusReason string       `json:\"statusReason\"`\n\tBody         *string      `json:\"body\"`\n\tHeaders      []HTTPHeader `json:\"headers\"`\n}\n\ntype HTTPResponseLog struct {\n\t// Will be the same ID as its related request ID.\n\tID           ulid.ULID    `json:\"id\"`\n\tProto        HTTPProtocol `json:\"proto\"`\n\tStatusCode   int          `json:\"statusCode\"`\n\tStatusReason string       `json:\"statusReason\"`\n\tBody         *string      `json:\"body\"`\n\tHeaders      []HTTPHeader `json:\"headers\"`\n}\n\ntype InterceptSettings struct {\n\tRequestsEnabled  bool    `json:\"requestsEnabled\"`\n\tResponsesEnabled bool    `json:\"responsesEnabled\"`\n\tRequestFilter    *string `json:\"requestFilter\"`\n\tResponseFilter   *string `json:\"responseFilter\"`\n}\n\ntype ModifyRequestInput struct {\n\tID             ulid.ULID         `json:\"id\"`\n\tURL            *url.URL          `json:\"url\"`\n\tMethod         HTTPMethod        `json:\"method\"`\n\tProto          HTTPProtocol      `json:\"proto\"`\n\tHeaders        []HTTPHeaderInput `json:\"headers\"`\n\tBody           *string           `json:\"body\"`\n\tModifyResponse *bool             `json:\"modifyResponse\"`\n}\n\ntype ModifyRequestResult struct {\n\tSuccess bool `json:\"success\"`\n}\n\ntype ModifyResponseInput struct {\n\tRequestID    ulid.ULID         `json:\"requestID\"`\n\tProto        HTTPProtocol      `json:\"proto\"`\n\tHeaders      []HTTPHeaderInput `json:\"headers\"`\n\tBody         *string           `json:\"body\"`\n\tStatusCode   int               `json:\"statusCode\"`\n\tStatusReason string            `json:\"statusReason\"`\n}\n\ntype ModifyResponseResult struct {\n\tSuccess bool `json:\"success\"`\n}\n\ntype Project struct {\n\tID       ulid.ULID        `json:\"id\"`\n\tName     string           `json:\"name\"`\n\tIsActive bool             `json:\"isActive\"`\n\tSettings *ProjectSettings `json:\"settings\"`\n}\n\ntype ProjectSettings struct {\n\tIntercept *InterceptSettings `json:\"intercept\"`\n}\n\ntype ScopeHeader struct {\n\tKey   *string `json:\"key\"`\n\tValue *string `json:\"value\"`\n}\n\ntype ScopeHeaderInput struct {\n\tKey   *string `json:\"key\"`\n\tValue *string `json:\"value\"`\n}\n\ntype ScopeRule struct {\n\tURL    *string      `json:\"url\"`\n\tHeader *ScopeHeader `json:\"header\"`\n\tBody   *string      `json:\"body\"`\n}\n\ntype ScopeRuleInput struct {\n\tURL    *string           `json:\"url\"`\n\tHeader *ScopeHeaderInput `json:\"header\"`\n\tBody   *string           `json:\"body\"`\n}\n\ntype SenderRequest struct {\n\tID                 ulid.ULID        `json:\"id\"`\n\tSourceRequestLogID *ulid.ULID       `json:\"sourceRequestLogID\"`\n\tURL                *url.URL         `json:\"url\"`\n\tMethod             HTTPMethod       `json:\"method\"`\n\tProto              HTTPProtocol     `json:\"proto\"`\n\tHeaders            []HTTPHeader     `json:\"headers\"`\n\tBody               *string          `json:\"body\"`\n\tTimestamp          time.Time        `json:\"timestamp\"`\n\tResponse           *HTTPResponseLog `json:\"response\"`\n}\n\ntype SenderRequestFilter struct {\n\tOnlyInScope      bool    `json:\"onlyInScope\"`\n\tSearchExpression *string `json:\"searchExpression\"`\n}\n\ntype SenderRequestFilterInput struct {\n\tOnlyInScope      *bool   `json:\"onlyInScope\"`\n\tSearchExpression *string `json:\"searchExpression\"`\n}\n\ntype SenderRequestInput struct {\n\tID      *ulid.ULID        `json:\"id\"`\n\tURL     *url.URL          `json:\"url\"`\n\tMethod  *HTTPMethod       `json:\"method\"`\n\tProto   *HTTPProtocol     `json:\"proto\"`\n\tHeaders []HTTPHeaderInput `json:\"headers\"`\n\tBody    *string           `json:\"body\"`\n}\n\ntype UpdateInterceptSettingsInput struct {\n\tRequestsEnabled  bool    `json:\"requestsEnabled\"`\n\tResponsesEnabled bool    `json:\"responsesEnabled\"`\n\tRequestFilter    *string `json:\"requestFilter\"`\n\tResponseFilter   *string `json:\"responseFilter\"`\n}\n\ntype HTTPMethod string\n\nconst (\n\tHTTPMethodGet     HTTPMethod = \"GET\"\n\tHTTPMethodHead    HTTPMethod = \"HEAD\"\n\tHTTPMethodPost    HTTPMethod = \"POST\"\n\tHTTPMethodPut     HTTPMethod = \"PUT\"\n\tHTTPMethodDelete  HTTPMethod = \"DELETE\"\n\tHTTPMethodConnect HTTPMethod = \"CONNECT\"\n\tHTTPMethodOptions HTTPMethod = \"OPTIONS\"\n\tHTTPMethodTrace   HTTPMethod = \"TRACE\"\n\tHTTPMethodPatch   HTTPMethod = \"PATCH\"\n)\n\nvar AllHTTPMethod = []HTTPMethod{\n\tHTTPMethodGet,\n\tHTTPMethodHead,\n\tHTTPMethodPost,\n\tHTTPMethodPut,\n\tHTTPMethodDelete,\n\tHTTPMethodConnect,\n\tHTTPMethodOptions,\n\tHTTPMethodTrace,\n\tHTTPMethodPatch,\n}\n\nfunc (e HTTPMethod) IsValid() bool {\n\tswitch e {\n\tcase HTTPMethodGet, HTTPMethodHead, HTTPMethodPost, HTTPMethodPut, HTTPMethodDelete, HTTPMethodConnect, HTTPMethodOptions, HTTPMethodTrace, HTTPMethodPatch:\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (e HTTPMethod) String() string {\n\treturn string(e)\n}\n\nfunc (e *HTTPMethod) UnmarshalGQL(v interface{}) error {\n\tstr, ok := v.(string)\n\tif !ok {\n\t\treturn fmt.Errorf(\"enums must be strings\")\n\t}\n\n\t*e = HTTPMethod(str)\n\tif !e.IsValid() {\n\t\treturn fmt.Errorf(\"%s is not a valid HttpMethod\", str)\n\t}\n\treturn nil\n}\n\nfunc (e HTTPMethod) MarshalGQL(w io.Writer) {\n\tfmt.Fprint(w, strconv.Quote(e.String()))\n}\n\ntype HTTPProtocol string\n\nconst (\n\tHTTPProtocolHTTP10 HTTPProtocol = \"HTTP10\"\n\tHTTPProtocolHTTP11 HTTPProtocol = \"HTTP11\"\n\tHTTPProtocolHTTP20 HTTPProtocol = \"HTTP20\"\n)\n\nvar AllHTTPProtocol = []HTTPProtocol{\n\tHTTPProtocolHTTP10,\n\tHTTPProtocolHTTP11,\n\tHTTPProtocolHTTP20,\n}\n\nfunc (e HTTPProtocol) IsValid() bool {\n\tswitch e {\n\tcase HTTPProtocolHTTP10, HTTPProtocolHTTP11, HTTPProtocolHTTP20:\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (e HTTPProtocol) String() string {\n\treturn string(e)\n}\n\nfunc (e *HTTPProtocol) UnmarshalGQL(v interface{}) error {\n\tstr, ok := v.(string)\n\tif !ok {\n\t\treturn fmt.Errorf(\"enums must be strings\")\n\t}\n\n\t*e = HTTPProtocol(str)\n\tif !e.IsValid() {\n\t\treturn fmt.Errorf(\"%s is not a valid HttpProtocol\", str)\n\t}\n\treturn nil\n}\n\nfunc (e HTTPProtocol) MarshalGQL(w io.Writer) {\n\tfmt.Fprint(w, strconv.Quote(e.String()))\n}\n"
  },
  {
    "path": "pkg/api/resolvers.go",
    "content": "package api\n\n//go:generate go run github.com/99designs/gqlgen\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/99designs/gqlgen/graphql\"\n\t\"github.com/oklog/ulid\"\n\t\"github.com/vektah/gqlparser/v2/gqlerror\"\n\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n\t\"github.com/dstotijn/hetty/pkg/proj\"\n\t\"github.com/dstotijn/hetty/pkg/proxy\"\n\t\"github.com/dstotijn/hetty/pkg/proxy/intercept\"\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n\t\"github.com/dstotijn/hetty/pkg/sender\"\n)\n\nvar httpProtocolMap = map[string]HTTPProtocol{\n\tsender.HTTPProto10: HTTPProtocolHTTP10,\n\tsender.HTTPProto11: HTTPProtocolHTTP11,\n\tsender.HTTPProto20: HTTPProtocolHTTP20,\n}\n\nvar revHTTPProtocolMap = map[HTTPProtocol]string{\n\tHTTPProtocolHTTP10: sender.HTTPProto10,\n\tHTTPProtocolHTTP11: sender.HTTPProto11,\n\tHTTPProtocolHTTP20: sender.HTTPProto20,\n}\n\ntype Resolver struct {\n\tProjectService    *proj.Service\n\tRequestLogService *reqlog.Service\n\tInterceptService  *intercept.Service\n\tSenderService     *sender.Service\n}\n\ntype (\n\tqueryResolver    struct{ *Resolver }\n\tmutationResolver struct{ *Resolver }\n)\n\nfunc (r *Resolver) Query() QueryResolver       { return &queryResolver{r} }\nfunc (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }\n\nfunc (r *queryResolver) HTTPRequestLogs(ctx context.Context) ([]HTTPRequestLog, error) {\n\treqs, err := r.RequestLogService.FindRequests(ctx)\n\tif errors.Is(err, proj.ErrNoProject) {\n\t\treturn nil, noActiveProjectErr(ctx)\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not query repository for requests: %w\", err)\n\t}\n\n\tlogs := make([]HTTPRequestLog, len(reqs))\n\n\tfor i, req := range reqs {\n\t\treq, err := parseRequestLog(req)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tlogs[i] = req\n\t}\n\n\treturn logs, nil\n}\n\nfunc (r *queryResolver) HTTPRequestLog(ctx context.Context, id ulid.ULID) (*HTTPRequestLog, error) {\n\tlog, err := r.RequestLogService.FindRequestLogByID(ctx, id)\n\tif errors.Is(err, reqlog.ErrRequestNotFound) {\n\t\treturn nil, nil\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not get request by ID: %w\", err)\n\t}\n\n\treq, err := parseRequestLog(log)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &req, nil\n}\n\nfunc parseRequestLog(reqLog reqlog.RequestLog) (HTTPRequestLog, error) {\n\tmethod := HTTPMethod(reqLog.Method)\n\tif method != \"\" && !method.IsValid() {\n\t\treturn HTTPRequestLog{}, fmt.Errorf(\"request has invalid method: %v\", method)\n\t}\n\n\tlog := HTTPRequestLog{\n\t\tID:        reqLog.ID,\n\t\tProto:     reqLog.Proto,\n\t\tMethod:    method,\n\t\tTimestamp: ulid.Time(reqLog.ID.Time()),\n\t}\n\n\tif reqLog.URL != nil {\n\t\tlog.URL = reqLog.URL.String()\n\t}\n\n\tif len(reqLog.Body) > 0 {\n\t\tbodyStr := string(reqLog.Body)\n\t\tlog.Body = &bodyStr\n\t}\n\n\tif reqLog.Header != nil {\n\t\tlog.Headers = make([]HTTPHeader, 0)\n\n\t\tfor key, values := range reqLog.Header {\n\t\t\tfor _, value := range values {\n\t\t\t\tlog.Headers = append(log.Headers, HTTPHeader{\n\t\t\t\t\tKey:   key,\n\t\t\t\t\tValue: value,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tsort.Sort(HTTPHeaders(log.Headers))\n\t}\n\n\tif reqLog.Response != nil {\n\t\tresLog, err := parseResponseLog(*reqLog.Response)\n\t\tif err != nil {\n\t\t\treturn HTTPRequestLog{}, err\n\t\t}\n\n\t\tresLog.ID = reqLog.ID\n\n\t\tlog.Response = &resLog\n\t}\n\n\treturn log, nil\n}\n\nfunc parseResponseLog(resLog reqlog.ResponseLog) (HTTPResponseLog, error) {\n\tproto := httpProtocolMap[resLog.Proto]\n\tif !proto.IsValid() {\n\t\treturn HTTPResponseLog{}, fmt.Errorf(\"sender response has invalid protocol: %v\", resLog.Proto)\n\t}\n\n\thttpResLog := HTTPResponseLog{\n\t\tProto:      proto,\n\t\tStatusCode: resLog.StatusCode,\n\t}\n\tstatusReasonSubs := strings.SplitN(resLog.Status, \" \", 2)\n\n\tif len(statusReasonSubs) == 2 {\n\t\thttpResLog.StatusReason = statusReasonSubs[1]\n\t}\n\n\tif len(resLog.Body) > 0 {\n\t\tbodyStr := string(resLog.Body)\n\t\thttpResLog.Body = &bodyStr\n\t}\n\n\tif resLog.Header != nil {\n\t\thttpResLog.Headers = make([]HTTPHeader, 0)\n\n\t\tfor key, values := range resLog.Header {\n\t\t\tfor _, value := range values {\n\t\t\t\thttpResLog.Headers = append(httpResLog.Headers, HTTPHeader{\n\t\t\t\t\tKey:   key,\n\t\t\t\t\tValue: value,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tsort.Sort(HTTPHeaders(httpResLog.Headers))\n\t}\n\n\treturn httpResLog, nil\n}\n\nfunc (r *mutationResolver) CreateProject(ctx context.Context, name string) (*Project, error) {\n\tp, err := r.ProjectService.CreateProject(ctx, name)\n\tif errors.Is(err, proj.ErrInvalidName) {\n\t\treturn nil, gqlerror.Errorf(\"Project name must only contain alphanumeric or space chars.\")\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not open project: %w\", err)\n\t}\n\n\tproject := parseProject(r.ProjectService, p)\n\n\treturn &project, nil\n}\n\nfunc (r *mutationResolver) OpenProject(ctx context.Context, id ulid.ULID) (*Project, error) {\n\tp, err := r.ProjectService.OpenProject(ctx, id)\n\tif errors.Is(err, proj.ErrInvalidName) {\n\t\treturn nil, gqlerror.Errorf(\"Project name must only contain alphanumeric or space chars.\")\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not open project: %w\", err)\n\t}\n\n\tproject := parseProject(r.ProjectService, p)\n\n\treturn &project, nil\n}\n\nfunc (r *queryResolver) ActiveProject(ctx context.Context) (*Project, error) {\n\tp, err := r.ProjectService.ActiveProject(ctx)\n\tif errors.Is(err, proj.ErrNoProject) {\n\t\treturn nil, nil\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not open project: %w\", err)\n\t}\n\n\tproject := parseProject(r.ProjectService, p)\n\n\treturn &project, nil\n}\n\nfunc (r *queryResolver) Projects(ctx context.Context) ([]Project, error) {\n\tp, err := r.ProjectService.Projects(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not get projects: %w\", err)\n\t}\n\n\tprojects := make([]Project, len(p))\n\tfor i, proj := range p {\n\t\tprojects[i] = parseProject(r.ProjectService, proj)\n\t}\n\n\treturn projects, nil\n}\n\nfunc (r *queryResolver) Scope(ctx context.Context) ([]ScopeRule, error) {\n\trules := r.ProjectService.Scope().Rules()\n\treturn scopeToScopeRules(rules), nil\n}\n\nfunc regexpToStringPtr(r *regexp.Regexp) *string {\n\tif r == nil {\n\t\treturn nil\n\t}\n\n\ts := r.String()\n\n\treturn &s\n}\n\nfunc (r *mutationResolver) CloseProject(ctx context.Context) (*CloseProjectResult, error) {\n\tif err := r.ProjectService.CloseProject(); err != nil {\n\t\treturn nil, fmt.Errorf(\"could not close project: %w\", err)\n\t}\n\n\treturn &CloseProjectResult{true}, nil\n}\n\nfunc (r *mutationResolver) DeleteProject(ctx context.Context, id ulid.ULID) (*DeleteProjectResult, error) {\n\tif err := r.ProjectService.DeleteProject(ctx, id); err != nil {\n\t\treturn nil, fmt.Errorf(\"could not delete project: %w\", err)\n\t}\n\n\treturn &DeleteProjectResult{\n\t\tSuccess: true,\n\t}, nil\n}\n\nfunc (r *mutationResolver) ClearHTTPRequestLog(ctx context.Context) (*ClearHTTPRequestLogResult, error) {\n\tproject, err := r.ProjectService.ActiveProject(ctx)\n\tif errors.Is(err, proj.ErrNoProject) {\n\t\treturn nil, noActiveProjectErr(ctx)\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not get active project: %w\", err)\n\t}\n\n\tif err := r.RequestLogService.ClearRequests(ctx, project.ID); err != nil {\n\t\treturn nil, fmt.Errorf(\"could not clear request log: %w\", err)\n\t}\n\n\treturn &ClearHTTPRequestLogResult{true}, nil\n}\n\nfunc (r *mutationResolver) SetScope(ctx context.Context, input []ScopeRuleInput) ([]ScopeRule, error) {\n\trules := make([]scope.Rule, len(input))\n\n\tfor i, rule := range input {\n\t\tu, err := stringPtrToRegexp(rule.URL)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid URL in scope rule: %w\", err)\n\t\t}\n\n\t\tvar headerKey, headerValue *regexp.Regexp\n\n\t\tif rule.Header != nil {\n\t\t\theaderKey, err = stringPtrToRegexp(rule.Header.Key)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid header key in scope rule: %w\", err)\n\t\t\t}\n\n\t\t\theaderValue, err = stringPtrToRegexp(rule.Header.Key)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid header value in scope rule: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tbody, err := stringPtrToRegexp(rule.Body)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid body in scope rule: %w\", err)\n\t\t}\n\n\t\trules[i] = scope.Rule{\n\t\t\tURL: u,\n\t\t\tHeader: scope.Header{\n\t\t\t\tKey:   headerKey,\n\t\t\t\tValue: headerValue,\n\t\t\t},\n\t\t\tBody: body,\n\t\t}\n\t}\n\n\terr := r.ProjectService.SetScopeRules(ctx, rules)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not set scope rules: %w\", err)\n\t}\n\n\treturn scopeToScopeRules(rules), nil\n}\n\nfunc (r *queryResolver) HTTPRequestLogFilter(ctx context.Context) (*HTTPRequestLogFilter, error) {\n\treturn findReqFilterToHTTPReqLogFilter(r.RequestLogService.FindReqsFilter()), nil\n}\n\nfunc (r *mutationResolver) SetHTTPRequestLogFilter(\n\tctx context.Context,\n\tinput *HTTPRequestLogFilterInput,\n) (*HTTPRequestLogFilter, error) {\n\tfilter, err := findRequestsFilterFromInput(input)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not parse request log filter: %w\", err)\n\t}\n\n\terr = r.ProjectService.SetRequestLogFindFilter(ctx, filter)\n\tif errors.Is(err, proj.ErrNoProject) {\n\t\treturn nil, noActiveProjectErr(ctx)\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not set request log filter: %w\", err)\n\t}\n\n\treturn findReqFilterToHTTPReqLogFilter(filter), nil\n}\n\nfunc (r *queryResolver) SenderRequest(ctx context.Context, id ulid.ULID) (*SenderRequest, error) {\n\tsenderReq, err := r.SenderService.FindRequestByID(ctx, id)\n\tif errors.Is(err, sender.ErrRequestNotFound) {\n\t\treturn nil, nil\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not get request by ID: %w\", err)\n\t}\n\n\treq, err := parseSenderRequest(senderReq)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &req, nil\n}\n\nfunc (r *queryResolver) SenderRequests(ctx context.Context) ([]SenderRequest, error) {\n\treqs, err := r.SenderService.FindRequests(ctx)\n\tif errors.Is(err, proj.ErrNoProject) {\n\t\treturn nil, noActiveProjectErr(ctx)\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to find sender requests: %w\", err)\n\t}\n\n\tsenderReqs := make([]SenderRequest, len(reqs))\n\n\tfor i, req := range reqs {\n\t\treq, err := parseSenderRequest(req)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tsenderReqs[i] = req\n\t}\n\n\treturn senderReqs, nil\n}\n\nfunc (r *mutationResolver) SetSenderRequestFilter(\n\tctx context.Context,\n\tinput *SenderRequestFilterInput,\n) (*SenderRequestFilter, error) {\n\tfilter, err := findSenderRequestsFilterFromInput(input)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not parse request log filter: %w\", err)\n\t}\n\n\terr = r.ProjectService.SetSenderRequestFindFilter(ctx, filter)\n\tif errors.Is(err, proj.ErrNoProject) {\n\t\treturn nil, noActiveProjectErr(ctx)\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not set request log filter: %w\", err)\n\t}\n\n\treturn findReqFilterToSenderReqFilter(filter), nil\n}\n\nfunc (r *mutationResolver) CreateOrUpdateSenderRequest(\n\tctx context.Context,\n\tinput SenderRequestInput,\n) (*SenderRequest, error) {\n\treq := sender.Request{\n\t\tURL:    input.URL,\n\t\tHeader: make(http.Header),\n\t}\n\n\tif input.ID != nil {\n\t\treq.ID = *input.ID\n\t}\n\n\tif input.Method != nil {\n\t\treq.Method = input.Method.String()\n\t}\n\n\tif input.Proto != nil {\n\t\treq.Proto = revHTTPProtocolMap[*input.Proto]\n\t}\n\n\tfor _, header := range input.Headers {\n\t\treq.Header.Add(header.Key, header.Value)\n\t}\n\n\tif input.Body != nil {\n\t\treq.Body = []byte(*input.Body)\n\t}\n\n\treq, err := r.SenderService.CreateOrUpdateRequest(ctx, req)\n\tif errors.Is(err, proj.ErrNoProject) {\n\t\treturn nil, noActiveProjectErr(ctx)\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not create sender request: %w\", err)\n\t}\n\n\tsenderReq, err := parseSenderRequest(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &senderReq, nil\n}\n\nfunc (r *mutationResolver) CreateSenderRequestFromHTTPRequestLog(\n\tctx context.Context,\n\tid ulid.ULID,\n) (*SenderRequest, error) {\n\treq, err := r.SenderService.CloneFromRequestLog(ctx, id)\n\tif errors.Is(err, proj.ErrNoProject) {\n\t\treturn nil, noActiveProjectErr(ctx)\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not create sender request from http request log: %w\", err)\n\t}\n\n\tsenderReq, err := parseSenderRequest(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &senderReq, nil\n}\n\nfunc (r *mutationResolver) SendRequest(ctx context.Context, id ulid.ULID) (*SenderRequest, error) {\n\t// Use new context, because we don't want to risk interrupting sending the request\n\t// or the subsequent storing of the response, e.g. if ctx gets cancelled or\n\t// times out.\n\tctx2 := context.Background()\n\n\tvar sendErr *sender.SendError\n\n\t//nolint:contextcheck\n\treq, err := r.SenderService.SendRequest(ctx2, id)\n\n\tswitch {\n\tcase errors.Is(err, proj.ErrNoProject):\n\t\treturn nil, noActiveProjectErr(ctx)\n\tcase errors.As(err, &sendErr):\n\t\treturn nil, &gqlerror.Error{\n\t\t\tPath:    graphql.GetPath(ctx),\n\t\t\tMessage: fmt.Sprintf(\"Sending request failed: %v\", sendErr.Unwrap()),\n\t\t\tExtensions: map[string]interface{}{\n\t\t\t\t\"code\": \"send_request_failed\",\n\t\t\t},\n\t\t}\n\tcase err != nil:\n\t\treturn nil, fmt.Errorf(\"could not send request: %w\", err)\n\t}\n\n\tsenderReq, err := parseSenderRequest(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &senderReq, nil\n}\n\nfunc (r *mutationResolver) DeleteSenderRequests(ctx context.Context) (*DeleteSenderRequestsResult, error) {\n\tproject, err := r.ProjectService.ActiveProject(ctx)\n\tif errors.Is(err, proj.ErrNoProject) {\n\t\treturn nil, noActiveProjectErr(ctx)\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not get active project: %w\", err)\n\t}\n\n\tif err := r.SenderService.DeleteRequests(ctx, project.ID); err != nil {\n\t\treturn nil, fmt.Errorf(\"could not clear request log: %w\", err)\n\t}\n\n\treturn &DeleteSenderRequestsResult{true}, nil\n}\n\nfunc (r *queryResolver) InterceptedRequests(ctx context.Context) (httpReqs []HTTPRequest, err error) {\n\titems := r.InterceptService.Items()\n\n\tfor _, item := range items {\n\t\treq, err := parseInterceptItem(item)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\thttpReqs = append(httpReqs, req)\n\t}\n\n\treturn httpReqs, nil\n}\n\nfunc (r *queryResolver) InterceptedRequest(ctx context.Context, id ulid.ULID) (*HTTPRequest, error) {\n\titem, err := r.InterceptService.ItemByID(id)\n\tif errors.Is(err, intercept.ErrRequestNotFound) {\n\t\treturn nil, nil\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not get request by ID: %w\", err)\n\t}\n\n\treq, err := parseInterceptItem(item)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &req, nil\n}\n\nfunc (r *mutationResolver) ModifyRequest(ctx context.Context, input ModifyRequestInput) (*ModifyRequestResult, error) {\n\tbody := \"\"\n\tif input.Body != nil {\n\t\tbody = *input.Body\n\t}\n\n\t//nolint:noctx\n\treq, err := http.NewRequest(input.Method.String(), input.URL.String(), strings.NewReader(body))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to construct HTTP request: %w\", err)\n\t}\n\n\tfor _, header := range input.Headers {\n\t\treq.Header.Add(header.Key, header.Value)\n\t}\n\n\terr = r.InterceptService.ModifyRequest(input.ID, req, input.ModifyResponse)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not modify http request: %w\", err)\n\t}\n\n\treturn &ModifyRequestResult{Success: true}, nil\n}\n\nfunc (r *mutationResolver) CancelRequest(ctx context.Context, id ulid.ULID) (*CancelRequestResult, error) {\n\terr := r.InterceptService.CancelRequest(id)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not cancel http request: %w\", err)\n\t}\n\n\treturn &CancelRequestResult{Success: true}, nil\n}\n\nfunc (r *mutationResolver) ModifyResponse(\n\tctx context.Context,\n\tinput ModifyResponseInput,\n) (*ModifyResponseResult, error) {\n\tres := &http.Response{\n\t\tHeader:     make(http.Header),\n\t\tStatus:     fmt.Sprintf(\"%v %v\", input.StatusCode, input.StatusReason),\n\t\tStatusCode: input.StatusCode,\n\t\tProto:      revHTTPProtocolMap[input.Proto],\n\t}\n\n\tvar ok bool\n\tif res.ProtoMajor, res.ProtoMinor, ok = http.ParseHTTPVersion(res.Proto); !ok {\n\t\treturn nil, fmt.Errorf(\"malformed HTTP version: %q\", res.Proto)\n\t}\n\n\tvar body string\n\tif input.Body != nil {\n\t\tbody = *input.Body\n\t}\n\n\tres.Body = io.NopCloser(strings.NewReader(body))\n\n\tfor _, header := range input.Headers {\n\t\tres.Header.Add(header.Key, header.Value)\n\t}\n\n\terr := r.InterceptService.ModifyResponse(input.RequestID, res)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not modify http request: %w\", err)\n\t}\n\n\treturn &ModifyResponseResult{Success: true}, nil\n}\n\nfunc (r *mutationResolver) CancelResponse(ctx context.Context, requestID ulid.ULID) (*CancelResponseResult, error) {\n\terr := r.InterceptService.CancelResponse(requestID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not cancel http response: %w\", err)\n\t}\n\n\treturn &CancelResponseResult{Success: true}, nil\n}\n\nfunc (r *mutationResolver) UpdateInterceptSettings(\n\tctx context.Context,\n\tinput UpdateInterceptSettingsInput,\n) (*InterceptSettings, error) {\n\tsettings := intercept.Settings{\n\t\tRequestsEnabled:  input.RequestsEnabled,\n\t\tResponsesEnabled: input.ResponsesEnabled,\n\t}\n\n\tif input.RequestFilter != nil && *input.RequestFilter != \"\" {\n\t\texpr, err := filter.ParseQuery(*input.RequestFilter)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not parse request filter: %w\", err)\n\t\t}\n\n\t\tsettings.RequestFilter = expr\n\t}\n\n\tif input.ResponseFilter != nil && *input.ResponseFilter != \"\" {\n\t\texpr, err := filter.ParseQuery(*input.ResponseFilter)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not parse response filter: %w\", err)\n\t\t}\n\n\t\tsettings.ResponseFilter = expr\n\t}\n\n\terr := r.ProjectService.UpdateInterceptSettings(ctx, settings)\n\tif errors.Is(err, proj.ErrNoProject) {\n\t\treturn nil, noActiveProjectErr(ctx)\n\t} else if err != nil {\n\t\treturn nil, fmt.Errorf(\"could not update intercept settings: %w\", err)\n\t}\n\n\tupdated := &InterceptSettings{\n\t\tRequestsEnabled:  settings.RequestsEnabled,\n\t\tResponsesEnabled: settings.ResponsesEnabled,\n\t}\n\n\tif settings.RequestFilter != nil {\n\t\treqFilter := settings.RequestFilter.String()\n\t\tupdated.RequestFilter = &reqFilter\n\t}\n\n\tif settings.ResponseFilter != nil {\n\t\tresFilter := settings.ResponseFilter.String()\n\t\tupdated.ResponseFilter = &resFilter\n\t}\n\n\treturn updated, nil\n}\n\nfunc parseSenderRequest(req sender.Request) (SenderRequest, error) {\n\tmethod := HTTPMethod(req.Method)\n\tif method != \"\" && !method.IsValid() {\n\t\treturn SenderRequest{}, fmt.Errorf(\"sender request has invalid method: %v\", method)\n\t}\n\n\treqProto := httpProtocolMap[req.Proto]\n\tif !reqProto.IsValid() {\n\t\treturn SenderRequest{}, fmt.Errorf(\"sender request has invalid protocol: %v\", req.Proto)\n\t}\n\n\tsenderReq := SenderRequest{\n\t\tID:        req.ID,\n\t\tURL:       req.URL,\n\t\tMethod:    method,\n\t\tProto:     HTTPProtocol(req.Proto),\n\t\tTimestamp: ulid.Time(req.ID.Time()),\n\t}\n\n\tif req.SourceRequestLogID.Compare(ulid.ULID{}) != 0 {\n\t\tsenderReq.SourceRequestLogID = &req.SourceRequestLogID\n\t}\n\n\tif req.Header != nil {\n\t\tsenderReq.Headers = make([]HTTPHeader, 0)\n\n\t\tfor key, values := range req.Header {\n\t\t\tfor _, value := range values {\n\t\t\t\tsenderReq.Headers = append(senderReq.Headers, HTTPHeader{\n\t\t\t\t\tKey:   key,\n\t\t\t\t\tValue: value,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tsort.Sort(HTTPHeaders(senderReq.Headers))\n\t}\n\n\tif len(req.Body) > 0 {\n\t\tbodyStr := string(req.Body)\n\t\tsenderReq.Body = &bodyStr\n\t}\n\n\tif req.Response != nil {\n\t\tresLog, err := parseResponseLog(*req.Response)\n\t\tif err != nil {\n\t\t\treturn SenderRequest{}, err\n\t\t}\n\n\t\tresLog.ID = req.ID\n\n\t\tsenderReq.Response = &resLog\n\t}\n\n\treturn senderReq, nil\n}\n\nfunc parseHTTPRequest(req *http.Request) (HTTPRequest, error) {\n\tmethod := HTTPMethod(req.Method)\n\tif method != \"\" && !method.IsValid() {\n\t\treturn HTTPRequest{}, fmt.Errorf(\"http request has invalid method: %v\", method)\n\t}\n\n\treqProto := httpProtocolMap[req.Proto]\n\tif !reqProto.IsValid() {\n\t\treturn HTTPRequest{}, fmt.Errorf(\"http request has invalid protocol: %v\", req.Proto)\n\t}\n\n\tid, ok := proxy.RequestIDFromContext(req.Context())\n\tif !ok {\n\t\treturn HTTPRequest{}, errors.New(\"http request has missing ID\")\n\t}\n\n\thttpReq := HTTPRequest{\n\t\tID:     id,\n\t\tURL:    req.URL,\n\t\tMethod: method,\n\t\tProto:  HTTPProtocol(req.Proto),\n\t}\n\n\tif req.Header != nil {\n\t\thttpReq.Headers = make([]HTTPHeader, 0)\n\n\t\tfor key, values := range req.Header {\n\t\t\tfor _, value := range values {\n\t\t\t\thttpReq.Headers = append(httpReq.Headers, HTTPHeader{\n\t\t\t\t\tKey:   key,\n\t\t\t\t\tValue: value,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tsort.Sort(HTTPHeaders(httpReq.Headers))\n\t}\n\n\tif req.Body != nil {\n\t\tbody, err := ioutil.ReadAll(req.Body)\n\t\tif err != nil {\n\t\t\treturn HTTPRequest{}, fmt.Errorf(\"failed to read request body: %w\", err)\n\t\t}\n\n\t\treq.Body = ioutil.NopCloser(bytes.NewBuffer(body))\n\t\tbodyStr := string(body)\n\t\thttpReq.Body = &bodyStr\n\t}\n\n\treturn httpReq, nil\n}\n\nfunc parseHTTPResponse(res *http.Response) (HTTPResponse, error) {\n\tresProto := httpProtocolMap[res.Proto]\n\tif !resProto.IsValid() {\n\t\treturn HTTPResponse{}, fmt.Errorf(\"http response has invalid protocol: %v\", res.Proto)\n\t}\n\n\tid, ok := proxy.RequestIDFromContext(res.Request.Context())\n\tif !ok {\n\t\treturn HTTPResponse{}, errors.New(\"http response has missing ID\")\n\t}\n\n\thttpRes := HTTPResponse{\n\t\tID:         id,\n\t\tProto:      resProto,\n\t\tStatusCode: res.StatusCode,\n\t}\n\n\tstatusReasonSubs := strings.SplitN(res.Status, \" \", 2)\n\n\tif len(statusReasonSubs) == 2 {\n\t\thttpRes.StatusReason = statusReasonSubs[1]\n\t}\n\n\tif res.Header != nil {\n\t\thttpRes.Headers = make([]HTTPHeader, 0)\n\n\t\tfor key, values := range res.Header {\n\t\t\tfor _, value := range values {\n\t\t\t\thttpRes.Headers = append(httpRes.Headers, HTTPHeader{\n\t\t\t\t\tKey:   key,\n\t\t\t\t\tValue: value,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tsort.Sort(HTTPHeaders(httpRes.Headers))\n\t}\n\n\tif res.Body != nil {\n\t\tbody, err := ioutil.ReadAll(res.Body)\n\t\tif err != nil {\n\t\t\treturn HTTPResponse{}, fmt.Errorf(\"failed to read response body: %w\", err)\n\t\t}\n\n\t\tres.Body = ioutil.NopCloser(bytes.NewBuffer(body))\n\t\tbodyStr := string(body)\n\t\thttpRes.Body = &bodyStr\n\t}\n\n\treturn httpRes, nil\n}\n\nfunc parseInterceptItem(item intercept.Item) (req HTTPRequest, err error) {\n\tif item.Response != nil {\n\t\treq, err = parseHTTPRequest(item.Response.Request)\n\t\tif err != nil {\n\t\t\treturn HTTPRequest{}, err\n\t\t}\n\n\t\tres, err := parseHTTPResponse(item.Response)\n\t\tif err != nil {\n\t\t\treturn HTTPRequest{}, err\n\t\t}\n\n\t\treq.Response = &res\n\t} else if item.Request != nil {\n\t\treq, err = parseHTTPRequest(item.Request)\n\t\tif err != nil {\n\t\t\treturn HTTPRequest{}, err\n\t\t}\n\t}\n\n\treturn req, nil\n}\n\nfunc parseProject(projSvc *proj.Service, p proj.Project) Project {\n\tproject := Project{\n\t\tID:       p.ID,\n\t\tName:     p.Name,\n\t\tIsActive: projSvc.IsProjectActive(p.ID),\n\t\tSettings: &ProjectSettings{\n\t\t\tIntercept: &InterceptSettings{\n\t\t\t\tRequestsEnabled:  p.Settings.InterceptRequests,\n\t\t\t\tResponsesEnabled: p.Settings.InterceptResponses,\n\t\t\t},\n\t\t},\n\t}\n\n\tif p.Settings.InterceptRequestFilter != nil {\n\t\tinterceptReqFilter := p.Settings.InterceptRequestFilter.String()\n\t\tproject.Settings.Intercept.RequestFilter = &interceptReqFilter\n\t}\n\n\tif p.Settings.InterceptResponseFilter != nil {\n\t\tinterceptResFilter := p.Settings.InterceptResponseFilter.String()\n\t\tproject.Settings.Intercept.ResponseFilter = &interceptResFilter\n\t}\n\n\treturn project\n}\n\nfunc stringPtrToRegexp(s *string) (*regexp.Regexp, error) {\n\tif s == nil {\n\t\treturn nil, nil\n\t}\n\n\treturn regexp.Compile(*s)\n}\n\nfunc scopeToScopeRules(rules []scope.Rule) []ScopeRule {\n\tscopeRules := make([]ScopeRule, len(rules))\n\tfor i, rule := range rules {\n\t\tscopeRules[i].URL = regexpToStringPtr(rule.URL)\n\t\tif rule.Header.Key != nil || rule.Header.Value != nil {\n\t\t\tscopeRules[i].Header = &ScopeHeader{\n\t\t\t\tKey:   regexpToStringPtr(rule.Header.Key),\n\t\t\t\tValue: regexpToStringPtr(rule.Header.Value),\n\t\t\t}\n\t\t}\n\n\t\tscopeRules[i].Body = regexpToStringPtr(rule.Body)\n\t}\n\n\treturn scopeRules\n}\n\nfunc findRequestsFilterFromInput(input *HTTPRequestLogFilterInput) (findFilter reqlog.FindRequestsFilter, err error) {\n\tif input == nil {\n\t\treturn\n\t}\n\n\tif input.OnlyInScope != nil {\n\t\tfindFilter.OnlyInScope = *input.OnlyInScope\n\t}\n\n\tif input.SearchExpression != nil && *input.SearchExpression != \"\" {\n\t\texpr, err := filter.ParseQuery(*input.SearchExpression)\n\t\tif err != nil {\n\t\t\treturn reqlog.FindRequestsFilter{}, fmt.Errorf(\"could not parse search query: %w\", err)\n\t\t}\n\n\t\tfindFilter.SearchExpr = expr\n\t}\n\n\treturn\n}\n\nfunc findSenderRequestsFilterFromInput(input *SenderRequestFilterInput) (findFilter sender.FindRequestsFilter, err error) {\n\tif input == nil {\n\t\treturn\n\t}\n\n\tif input.OnlyInScope != nil {\n\t\tfindFilter.OnlyInScope = *input.OnlyInScope\n\t}\n\n\tif input.SearchExpression != nil && *input.SearchExpression != \"\" {\n\t\texpr, err := filter.ParseQuery(*input.SearchExpression)\n\t\tif err != nil {\n\t\t\treturn sender.FindRequestsFilter{}, fmt.Errorf(\"could not parse search query: %w\", err)\n\t\t}\n\n\t\tfindFilter.SearchExpr = expr\n\t}\n\n\treturn\n}\n\nfunc findReqFilterToHTTPReqLogFilter(findReqFilter reqlog.FindRequestsFilter) *HTTPRequestLogFilter {\n\tempty := reqlog.FindRequestsFilter{}\n\tif findReqFilter == empty {\n\t\treturn nil\n\t}\n\n\thttpReqLogFilter := &HTTPRequestLogFilter{\n\t\tOnlyInScope: findReqFilter.OnlyInScope,\n\t}\n\n\tif findReqFilter.SearchExpr != nil {\n\t\tsearchExpr := findReqFilter.SearchExpr.String()\n\t\thttpReqLogFilter.SearchExpression = &searchExpr\n\t}\n\n\treturn httpReqLogFilter\n}\n\nfunc findReqFilterToSenderReqFilter(findReqFilter sender.FindRequestsFilter) *SenderRequestFilter {\n\tempty := sender.FindRequestsFilter{}\n\tif findReqFilter == empty {\n\t\treturn nil\n\t}\n\n\tsenderReqFilter := &SenderRequestFilter{\n\t\tOnlyInScope: findReqFilter.OnlyInScope,\n\t}\n\n\tif findReqFilter.SearchExpr != nil {\n\t\tsearchExpr := findReqFilter.SearchExpr.String()\n\t\tsenderReqFilter.SearchExpression = &searchExpr\n\t}\n\n\treturn senderReqFilter\n}\n\nfunc noActiveProjectErr(ctx context.Context) error {\n\treturn &gqlerror.Error{\n\t\tPath:    graphql.GetPath(ctx),\n\t\tMessage: \"No active project.\",\n\t\tExtensions: map[string]interface{}{\n\t\t\t\"code\": \"no_active_project\",\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/api/schema.graphql",
    "content": "type HttpRequestLog {\n  id: ID!\n  url: String!\n  method: HttpMethod!\n  proto: String!\n  headers: [HttpHeader!]!\n  body: String\n  timestamp: Time!\n  response: HttpResponseLog\n}\n\ntype HttpResponseLog {\n  \"\"\"\n  Will be the same ID as its related request ID.\n  \"\"\"\n  id: ID!\n  proto: HttpProtocol!\n  statusCode: Int!\n  statusReason: String!\n  body: String\n  headers: [HttpHeader!]!\n}\n\ntype HttpHeader {\n  key: String!\n  value: String!\n}\n\ntype Project {\n  id: ID!\n  name: String!\n  isActive: Boolean!\n  settings: ProjectSettings!\n}\n\ntype ProjectSettings {\n  intercept: InterceptSettings!\n}\n\ntype ScopeRule {\n  url: Regexp\n  header: ScopeHeader\n  body: Regexp\n}\n\ninput ScopeRuleInput {\n  url: Regexp\n  header: ScopeHeaderInput\n  body: Regexp\n}\n\ntype ScopeHeader {\n  key: Regexp\n  value: Regexp\n}\n\ninput ScopeHeaderInput {\n  key: Regexp\n  value: Regexp\n}\n\ntype CloseProjectResult {\n  success: Boolean!\n}\n\ntype DeleteProjectResult {\n  success: Boolean!\n}\n\ntype ClearHTTPRequestLogResult {\n  success: Boolean!\n}\n\ntype DeleteSenderRequestsResult {\n  success: Boolean!\n}\n\ninput HttpRequestLogFilterInput {\n  onlyInScope: Boolean\n  searchExpression: String\n}\n\ntype HttpRequestLogFilter {\n  onlyInScope: Boolean!\n  searchExpression: String\n}\n\ninput SenderRequestInput {\n  id: ID\n  url: URL!\n  method: HttpMethod\n  proto: HttpProtocol\n  headers: [HttpHeaderInput!]\n  body: String\n}\n\ninput HttpHeaderInput {\n  key: String!\n  value: String!\n}\n\ntype SenderRequest {\n  id: ID!\n  sourceRequestLogID: ID\n  url: URL!\n  method: HttpMethod!\n  proto: HttpProtocol!\n  headers: [HttpHeader!]\n  body: String\n  timestamp: Time!\n  response: HttpResponseLog\n}\n\ninput SenderRequestFilterInput {\n  onlyInScope: Boolean\n  searchExpression: String\n}\n\ntype SenderRequestFilter {\n  onlyInScope: Boolean!\n  searchExpression: String\n}\n\ntype HttpRequest {\n  id: ID!\n  url: URL!\n  method: HttpMethod!\n  proto: HttpProtocol!\n  headers: [HttpHeader!]!\n  body: String\n  response: HttpResponse\n}\n\ntype HttpResponse {\n  \"\"\"\n  Will be the same ID as its related request ID.\n  \"\"\"\n  id: ID!\n  proto: HttpProtocol!\n  statusCode: Int!\n  statusReason: String!\n  body: String\n  headers: [HttpHeader!]!\n}\n\ninput ModifyRequestInput {\n  id: ID!\n  url: URL!\n  method: HttpMethod!\n  proto: HttpProtocol!\n  headers: [HttpHeaderInput!]\n  body: String\n  modifyResponse: Boolean\n}\n\ntype ModifyRequestResult {\n  success: Boolean!\n}\n\ntype CancelRequestResult {\n  success: Boolean!\n}\n\ninput ModifyResponseInput {\n  requestID: ID!\n  proto: HttpProtocol!\n  headers: [HttpHeaderInput!]\n  body: String\n  statusCode: Int!\n  statusReason: String!\n}\n\ntype ModifyResponseResult {\n  success: Boolean!\n}\n\ntype CancelResponseResult {\n  success: Boolean!\n}\n\ninput UpdateInterceptSettingsInput {\n  requestsEnabled: Boolean!\n  responsesEnabled: Boolean!\n  requestFilter: String\n  responseFilter: String\n}\n\ntype InterceptSettings {\n  requestsEnabled: Boolean!\n  responsesEnabled: Boolean!\n  requestFilter: String\n  responseFilter: String\n}\n\ntype Query {\n  httpRequestLog(id: ID!): HttpRequestLog\n  httpRequestLogs: [HttpRequestLog!]!\n  httpRequestLogFilter: HttpRequestLogFilter\n  activeProject: Project\n  projects: [Project!]!\n  scope: [ScopeRule!]!\n  senderRequest(id: ID!): SenderRequest\n  senderRequests: [SenderRequest!]!\n  interceptedRequests: [HttpRequest!]!\n  interceptedRequest(id: ID!): HttpRequest\n}\n\ntype Mutation {\n  createProject(name: String!): Project\n  openProject(id: ID!): Project\n  closeProject: CloseProjectResult!\n  deleteProject(id: ID!): DeleteProjectResult!\n  clearHTTPRequestLog: ClearHTTPRequestLogResult!\n  setScope(scope: [ScopeRuleInput!]!): [ScopeRule!]!\n  setHttpRequestLogFilter(\n    filter: HttpRequestLogFilterInput\n  ): HttpRequestLogFilter\n  setSenderRequestFilter(filter: SenderRequestFilterInput): SenderRequestFilter\n  createOrUpdateSenderRequest(request: SenderRequestInput!): SenderRequest!\n  createSenderRequestFromHttpRequestLog(id: ID!): SenderRequest!\n  sendRequest(id: ID!): SenderRequest!\n  deleteSenderRequests: DeleteSenderRequestsResult!\n  modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!\n  cancelRequest(id: ID!): CancelRequestResult!\n  modifyResponse(response: ModifyResponseInput!): ModifyResponseResult!\n  cancelResponse(requestID: ID!): CancelResponseResult!\n  updateInterceptSettings(\n    input: UpdateInterceptSettingsInput!\n  ): InterceptSettings!\n}\n\nenum HttpMethod {\n  GET\n  HEAD\n  POST\n  PUT\n  DELETE\n  CONNECT\n  OPTIONS\n  TRACE\n  PATCH\n}\n\nenum HttpProtocol {\n  HTTP10\n  HTTP11\n  HTTP20\n}\n\nscalar Time\nscalar Regexp\nscalar URL\n"
  },
  {
    "path": "pkg/chrome/chrome.go",
    "content": "package chrome\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/chromedp/chromedp\"\n)\n\nvar defaultOpts = []chromedp.ExecAllocatorOption{\n\tchromedp.NoFirstRun,\n\tchromedp.NoDefaultBrowserCheck,\n\tchromedp.IgnoreCertErrors,\n\tchromedp.Flag(\"test-type \", true), // This prevents the `ignore-certificate-errors` warning.\n}\n\ntype Config struct {\n\tProxyServer      string\n\tProxyBypassHosts []string\n}\n\n// NewExecAllocator returns a new context setup with a chromedp.ExecAllocator.\n// Its `context.Context` return value can be used to create subsequent contexts for interacting\n// with an allocated Chrome browser.\nfunc NewExecAllocator(ctx context.Context, cfg Config) (context.Context, context.CancelFunc) {\n\tproxyBypass := strings.Join(append([]string{\"<-loopback\"}, cfg.ProxyBypassHosts...), \";\")\n\t//nolint:gocritic\n\topts := append(defaultOpts,\n\t\tchromedp.ProxyServer(cfg.ProxyServer),\n\t\tchromedp.Flag(\"proxy-bypass-list\", proxyBypass),\n\t)\n\n\treturn chromedp.NewExecAllocator(ctx, opts...)\n}\n"
  },
  {
    "path": "pkg/db/bolt/bolt.go",
    "content": "package bolt\n\nimport (\n\t\"fmt\"\n\n\tbolt \"go.etcd.io/bbolt\"\n)\n\n// Database is used to store and retrieve data from an underlying Bolt database.\ntype Database struct {\n\tbolt *bolt.DB\n}\n\n// OpenDatabase opens a new Bolt database.\nfunc OpenDatabase(path string, opts *bolt.Options) (*Database, error) {\n\tdb, err := bolt.Open(path, 0o600, opts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"bolt: failed to open database: %w\", err)\n\t}\n\n\treturn DatabaseFromBoltDB(db)\n}\n\n// Close closes the underlying Bolt database.\nfunc (db *Database) Close() error {\n\treturn db.bolt.Close()\n}\n\n// DatabaseFromBoltDB returns a Database with `db` set as the underlying Bolt\n// database.\nfunc DatabaseFromBoltDB(db *bolt.DB) (*Database, error) {\n\terr := db.Update(func(tx *bolt.Tx) error {\n\t\t_, err := tx.CreateBucketIfNotExists(projectsBucketName)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"bolt: failed to create projects bucket: %w\", err)\n\t}\n\n\treturn &Database{bolt: db}, nil\n}\n\nfunc createNestedBucket(tx *bolt.Tx, names ...[]byte) (b *bolt.Bucket, err error) {\n\tfor i, name := range names {\n\t\tif b == nil {\n\t\t\tb, err = tx.CreateBucketIfNotExists(name)\n\t\t} else {\n\t\t\tb, err = b.CreateBucketIfNotExists(name)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"bolt: failed to create nested bucket %q: %w\", names[:i+1], err)\n\t\t}\n\t}\n\n\treturn b, nil\n}\n"
  },
  {
    "path": "pkg/db/bolt/logger.go",
    "content": "package bolt\n\nimport (\n\tbolt \"go.etcd.io/bbolt\"\n\t\"go.uber.org/zap\"\n)\n\n// Interface guard.\nvar _ bolt.Logger = (*Logger)(nil)\n\ntype Logger struct {\n\t*zap.SugaredLogger\n}\n\n// Warning implements bbolt.Logger.\nfunc (l *Logger) Warning(v ...interface{}) {\n\tl.Warn(v...)\n}\n\n// Warningf implements bbolt.Logger.\nfunc (l *Logger) Warningf(format string, v ...interface{}) {\n\tl.Warnf(format, v...)\n}\n"
  },
  {
    "path": "pkg/db/bolt/proj.go",
    "content": "package bolt\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/gob\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/oklog/ulid\"\n\tbolt \"go.etcd.io/bbolt\"\n\n\t\"github.com/dstotijn/hetty/pkg/proj\"\n)\n\nvar (\n\tErrProjectsBucketNotFound = errors.New(\"bolt: projects bucket not found\")\n\tErrProjectBucketNotFound  = errors.New(\"bolt: project bucket not found\")\n)\n\nvar (\n\tprojectsBucketName = []byte(\"projects\")\n\tprojectKey         = []byte(\"project\")\n)\n\nfunc projectsBucket(tx *bolt.Tx) (*bolt.Bucket, error) {\n\tb := tx.Bucket(projectsBucketName)\n\tif b == nil {\n\t\treturn nil, ErrProjectsBucketNotFound\n\t}\n\n\treturn b, nil\n}\n\nfunc projectBucket(tx *bolt.Tx, projectID []byte) (*bolt.Bucket, error) {\n\tpb, err := projectsBucket(tx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tb := pb.Bucket(projectID[:])\n\tif b == nil {\n\t\treturn nil, ErrProjectBucketNotFound\n\t}\n\n\treturn b, nil\n}\n\nfunc (db *Database) UpsertProject(ctx context.Context, project proj.Project) error {\n\tbuf := bytes.Buffer{}\n\n\terr := gob.NewEncoder(&buf).Encode(project)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bolt: failed to encode project: %w\", err)\n\t}\n\n\terr = db.bolt.Update(func(tx *bolt.Tx) error {\n\t\tb, err := createNestedBucket(tx, projectsBucketName, project.ID[:])\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"bolt: failed to create project bucket: %w\", err)\n\t\t}\n\n\t\terr = b.Put(projectKey, buf.Bytes())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"bolt: failed to upsert project: %w\", err)\n\t\t}\n\n\t\t_, err = b.CreateBucketIfNotExists(reqLogsBucketName)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"bolt: failed to create request logs bucket: %w\", err)\n\t\t}\n\n\t\t_, err = b.CreateBucketIfNotExists(senderReqsBucketName)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"bolt: failed to create sender requests bucket: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bolt: failed to commit transaction: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (db *Database) FindProjectByID(ctx context.Context, projectID ulid.ULID) (project proj.Project, err error) {\n\terr = db.bolt.View(func(tx *bolt.Tx) error {\n\t\tbucket, err := projectBucket(tx, projectID[:])\n\t\tif errors.Is(err, ErrProjectsBucketNotFound) || errors.Is(err, ErrProjectBucketNotFound) {\n\t\t\treturn proj.ErrProjectNotFound\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\trawProject := bucket.Get(projectKey)\n\t\tif rawProject == nil {\n\t\t\treturn proj.ErrProjectNotFound\n\t\t}\n\n\t\terr = gob.NewDecoder(bytes.NewReader(rawProject)).Decode(&project)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decode project: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn proj.Project{}, fmt.Errorf(\"bolt: failed to commit transaction: %w\", err)\n\t}\n\n\treturn project, nil\n}\n\nfunc (db *Database) DeleteProject(ctx context.Context, projectID ulid.ULID) error {\n\terr := db.bolt.Update(func(tx *bolt.Tx) error {\n\t\tpb, err := projectsBucket(tx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\terr = pb.DeleteBucket(projectID[:])\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to delete project bucket: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bolt: failed to commit transaction: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (db *Database) Projects(ctx context.Context) ([]proj.Project, error) {\n\tprojects := make([]proj.Project, 0)\n\n\terr := db.bolt.View(func(tx *bolt.Tx) error {\n\t\tpb, err := projectsBucket(tx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\terr = pb.ForEachBucket(func(projectID []byte) error {\n\t\t\tbucket, err := projectBucket(tx, projectID)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\trawProject := bucket.Get(projectKey)\n\t\t\tif rawProject == nil {\n\t\t\t\treturn proj.ErrProjectNotFound\n\t\t\t}\n\n\t\t\tvar project proj.Project\n\t\t\terr = gob.NewDecoder(bytes.NewReader(rawProject)).Decode(&project)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"bolt: failed to decode project: %w\", err)\n\t\t\t}\n\t\t\tprojects = append(projects, project)\n\t\t\treturn nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"bolt: failed to iterate over projects: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"bolt: failed to commit transaction: %w\", err)\n\t}\n\n\treturn projects, nil\n}\n"
  },
  {
    "path": "pkg/db/bolt/proj_test.go",
    "content": "package bolt_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/gob\"\n\t\"errors\"\n\t\"math/rand\"\n\t\"regexp\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\t\"github.com/oklog/ulid\"\n\t\"go.etcd.io/bbolt\"\n\n\t\"github.com/dstotijn/hetty/pkg/db/bolt\"\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n\t\"github.com/dstotijn/hetty/pkg/proj\"\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n)\n\n//nolint:gosec\nvar ulidEntropy = rand.New(rand.NewSource(time.Now().UnixNano()))\n\nvar regexpCompareOpt = cmp.Comparer(func(x, y *regexp.Regexp) bool {\n\tswitch {\n\tcase x == nil && y == nil:\n\t\treturn true\n\tcase x == nil || y == nil:\n\t\treturn false\n\tdefault:\n\t\treturn x.String() == y.String()\n\t}\n})\n\nfunc TestUpsertProject(t *testing.T) {\n\tt.Parallel()\n\n\tpath := t.TempDir() + \"bolt.db\"\n\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t}\n\n\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t}\n\tdefer db.Close()\n\n\tsearchExpr, err := filter.ParseQuery(\"foo AND bar OR NOT baz\")\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error (expected: nil, got: %v)\", err)\n\t}\n\n\texp := proj.Project{\n\t\tID:   ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy),\n\t\tName: \"foobar\",\n\t\tSettings: proj.Settings{\n\t\t\tReqLogBypassOutOfScope: true,\n\t\t\tReqLogOnlyFindInScope:  true,\n\t\t\tReqLogSearchExpr:       searchExpr,\n\t\t\tScopeRules: []scope.Rule{\n\t\t\t\t{\n\t\t\t\t\tURL: regexp.MustCompile(\"^https://(.*)example.com(.*)$\"),\n\t\t\t\t\tHeader: scope.Header{\n\t\t\t\t\t\tKey:   regexp.MustCompile(\"^X-Foo(.*)$\"),\n\t\t\t\t\t\tValue: regexp.MustCompile(\"^foo(.*)$\"),\n\t\t\t\t\t},\n\t\t\t\t\tBody: regexp.MustCompile(\"^foo(.*)\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr = db.UpsertProject(context.Background(), exp)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error storing project: %v\", err)\n\t}\n\n\tvar rawProject []byte\n\n\terr = boltDB.View(func(tx *bbolt.Tx) error {\n\t\trawProject = tx.Bucket([]byte(\"projects\")).Bucket(exp.ID[:]).Get([]byte(\"project\"))\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error retrieving project from database: %v\", err)\n\t}\n\tif rawProject == nil {\n\t\tt.Fatalf(\"expected raw project to be retrieved, got: nil\")\n\t}\n\n\tgot := proj.Project{}\n\n\terr = gob.NewDecoder(bytes.NewReader(rawProject)).Decode(&got)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error decoding project: %v\", err)\n\t}\n\n\tif diff := cmp.Diff(exp, got, regexpCompareOpt, cmpopts.IgnoreUnexported(proj.Project{})); diff != \"\" {\n\t\tt.Fatalf(\"project not equal (-exp, +got):\\n%v\", diff)\n\t}\n}\n\nfunc TestFindProjectByID(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"existing project\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tpath := t.TempDir() + \"bolt.db\"\n\t\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t\t}\n\n\t\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t\t}\n\t\tdefer db.Close()\n\n\t\texp := proj.Project{\n\t\t\tID: ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy),\n\t\t}\n\n\t\tbuf := bytes.Buffer{}\n\n\t\terr = gob.NewEncoder(&buf).Encode(exp)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error encoding project: %v\", err)\n\t\t}\n\n\t\terr = boltDB.Update(func(tx *bbolt.Tx) error {\n\t\t\tb, err := tx.Bucket([]byte(\"projects\")).CreateBucket(exp.ID[:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn b.Put([]byte(\"project\"), buf.Bytes())\n\t\t})\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error setting project: %v\", err)\n\t\t}\n\n\t\tgot, err := db.FindProjectByID(context.Background(), exp.ID)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error finding project: %v\", err)\n\t\t}\n\n\t\tif diff := cmp.Diff(exp, got, cmpopts.IgnoreUnexported(proj.Project{})); diff != \"\" {\n\t\t\tt.Fatalf(\"project not equal (-exp, +got):\\n%v\", diff)\n\t\t}\n\t})\n\n\tt.Run(\"project not found\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tpath := t.TempDir() + \"bolt.db\"\n\t\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t\t}\n\n\t\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t\t}\n\t\tdefer db.Close()\n\n\t\tprojectID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\n\t\t_, err = db.FindProjectByID(context.Background(), projectID)\n\t\tif !errors.Is(err, proj.ErrProjectNotFound) {\n\t\t\tt.Fatalf(\"expected `proj.ErrProjectNotFound`, got: %v\", err)\n\t\t}\n\t})\n}\n\nfunc TestDeleteProject(t *testing.T) {\n\tt.Parallel()\n\n\tpath := t.TempDir() + \"bolt.db\"\n\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t}\n\n\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t}\n\tdefer db.Close()\n\n\t// Insert test fixture.\n\tprojectID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\terr = db.UpsertProject(context.Background(), proj.Project{\n\t\tID: projectID,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error storing project: %v\", err)\n\t}\n\n\terr = db.DeleteProject(context.Background(), projectID)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error deleting project: %v\", err)\n\t}\n\n\tvar got *bbolt.Bucket\n\terr = boltDB.View(func(tx *bbolt.Tx) error {\n\t\tgot = tx.Bucket([]byte(\"projects\")).Bucket(projectID[:])\n\t\treturn nil\n\t})\n\tif got != nil {\n\t\tt.Fatalf(\"expected bucket to be nil, got: %v\", got)\n\t}\n}\n\nfunc TestProjects(t *testing.T) {\n\tt.Parallel()\n\n\tpath := t.TempDir() + \"bolt.db\"\n\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t}\n\n\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t}\n\tdefer db.Close()\n\n\texp := []proj.Project{\n\t\t{\n\t\t\tID:   ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy),\n\t\t\tName: \"one\",\n\t\t},\n\t\t{\n\t\t\tID:   ulid.MustNew(ulid.Timestamp(time.Now())+100, ulidEntropy),\n\t\t\tName: \"two\",\n\t\t},\n\t}\n\n\t// Store fixtures.\n\tfor _, project := range exp {\n\t\terr = db.UpsertProject(context.Background(), project)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error creating project fixture: %v\", err)\n\t\t}\n\t}\n\n\tgot, err := db.Projects(context.Background())\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error finding projects: %v\", err)\n\t}\n\n\tif len(exp) != len(got) {\n\t\tt.Fatalf(\"expected %v projects, got: %v\", len(exp), len(got))\n\t}\n\n\tif diff := cmp.Diff(exp, got, cmpopts.IgnoreUnexported(proj.Project{})); diff != \"\" {\n\t\tt.Fatalf(\"projects not equal (-exp, +got):\\n%v\", diff)\n\t}\n}\n"
  },
  {
    "path": "pkg/db/bolt/reqlog.go",
    "content": "package bolt\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/gob\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/oklog/ulid\"\n\tbolt \"go.etcd.io/bbolt\"\n\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n)\n\nvar ErrRequestLogsBucketNotFound = errors.New(\"bolt: request logs bucket not found\")\n\nvar reqLogsBucketName = []byte(\"request_logs\")\n\nfunc requestLogsBucket(tx *bolt.Tx, projectID ulid.ULID) (*bolt.Bucket, error) {\n\tpb, err := projectBucket(tx, projectID[:])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tb := pb.Bucket(reqLogsBucketName)\n\tif b == nil {\n\t\treturn nil, ErrRequestLogsBucketNotFound\n\t}\n\n\treturn b, nil\n}\n\nfunc (db *Database) FindRequestLogs(ctx context.Context, filter reqlog.FindRequestsFilter, scope *scope.Scope) (reqLogs []reqlog.RequestLog, err error) {\n\tif filter.ProjectID.Compare(ulid.ULID{}) == 0 {\n\t\treturn nil, reqlog.ErrProjectIDMustBeSet\n\t}\n\n\ttx, err := db.bolt.Begin(false)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"bolt: failed to begin transaction: %w\", err)\n\t}\n\tdefer tx.Rollback()\n\n\tb, err := requestLogsBucket(tx, filter.ProjectID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"bolt: failed to get request logs bucket: %w\", err)\n\t}\n\n\terr = b.ForEach(func(reqLogID, rawReqLog []byte) error {\n\t\tvar reqLog reqlog.RequestLog\n\t\terr = gob.NewDecoder(bytes.NewReader(rawReqLog)).Decode(&reqLog)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decode request log: %w\", err)\n\t\t}\n\n\t\tif filter.OnlyInScope && !reqLog.MatchScope(scope) {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Filter by search expression. TODO: Once pagination is introduced,\n\t\t// this filter logic should be done as items are retrieved.\n\t\tif filter.SearchExpr != nil {\n\t\t\tmatch, err := reqLog.Matches(filter.SearchExpr)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to match search expression for request log (id: %v): %w\", reqLogID, err)\n\t\t\t}\n\n\t\t\tif !match {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\treqLogs = append(reqLogs, reqLog)\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"bolt: failed to iterate over request logs: %w\", err)\n\t}\n\n\t// Reverse items, so newest requests appear first.\n\tfor i, j := 0, len(reqLogs)-1; i < j; i, j = i+1, j-1 {\n\t\treqLogs[i], reqLogs[j] = reqLogs[j], reqLogs[i]\n\t}\n\n\treturn reqLogs, nil\n}\n\nfunc (db *Database) FindRequestLogByID(ctx context.Context, projectID, reqLogID ulid.ULID) (reqLog reqlog.RequestLog, err error) {\n\terr = db.bolt.View(func(tx *bolt.Tx) error {\n\t\tb, err := requestLogsBucket(tx, projectID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"bolt: failed to get request logs bucket: %w\", err)\n\t\t}\n\t\trawReqLog := b.Get(reqLogID[:])\n\t\tif rawReqLog == nil {\n\t\t\treturn reqlog.ErrRequestNotFound\n\t\t}\n\n\t\terr = gob.NewDecoder(bytes.NewReader(rawReqLog)).Decode(&reqLog)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decode request log: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn reqlog.RequestLog{}, fmt.Errorf(\"bolt: failed to find request log by ID: %w\", err)\n\t}\n\n\treturn reqLog, nil\n}\n\nfunc (db *Database) StoreRequestLog(ctx context.Context, reqLog reqlog.RequestLog) error {\n\tbuf := bytes.Buffer{}\n\n\terr := gob.NewEncoder(&buf).Encode(reqLog)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bolt: failed to encode request log: %w\", err)\n\t}\n\n\terr = db.bolt.Update(func(txn *bolt.Tx) error {\n\t\tb, err := requestLogsBucket(txn, reqLog.ProjectID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get request logs bucket: %w\", err)\n\t\t}\n\n\t\terr = b.Put(reqLog.ID[:], buf.Bytes())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to put request log: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bolt: failed to commit transaction: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (db *Database) StoreResponseLog(ctx context.Context, projectID, reqLogID ulid.ULID, resLog reqlog.ResponseLog) error {\n\tbuf := bytes.Buffer{}\n\n\terr := gob.NewEncoder(&buf).Encode(resLog)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bolt: failed to encode response log: %w\", err)\n\t}\n\n\terr = db.bolt.Update(func(txn *bolt.Tx) error {\n\t\tb, err := requestLogsBucket(txn, projectID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get request logs bucket: %w\", err)\n\t\t}\n\n\t\trawReqLog := b.Get(reqLogID[:])\n\t\tif rawReqLog == nil {\n\t\t\treturn reqlog.ErrRequestNotFound\n\t\t}\n\n\t\tvar reqLog reqlog.RequestLog\n\t\terr = gob.NewDecoder(bytes.NewReader(rawReqLog)).Decode(&reqLog)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decode request log: %w\", err)\n\t\t}\n\n\t\treqLog.Response = &resLog\n\n\t\tbuf := bytes.Buffer{}\n\t\terr = gob.NewEncoder(&buf).Encode(reqLog)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to encode request log: %w\", err)\n\t\t}\n\n\t\terr = b.Put(reqLog.ID[:], buf.Bytes())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to put request log: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bolt: failed to commit transaction: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (db *Database) ClearRequestLogs(ctx context.Context, projectID ulid.ULID) error {\n\terr := db.bolt.Update(func(txn *bolt.Tx) error {\n\t\tpb, err := projectBucket(txn, projectID[:])\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get project bucket: %w\", err)\n\t\t}\n\n\t\treturn pb.DeleteBucket(reqLogsBucketName)\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bolt: failed to commit transaction: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/db/bolt/reqlog_test.go",
    "content": "package bolt_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/oklog/ulid\"\n\t\"go.etcd.io/bbolt\"\n\n\t\"github.com/dstotijn/hetty/pkg/db/bolt\"\n\t\"github.com/dstotijn/hetty/pkg/proj\"\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n)\n\nfunc TestFindRequestLogs(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"without project ID in filter\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tpath := t.TempDir() + \"bolt.db\"\n\t\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t\t}\n\n\t\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t\t}\n\t\tdefer db.Close()\n\n\t\tfilter := reqlog.FindRequestsFilter{}\n\n\t\t_, err = db.FindRequestLogs(context.Background(), filter, nil)\n\t\tif !errors.Is(err, reqlog.ErrProjectIDMustBeSet) {\n\t\t\tt.Fatalf(\"expected `reqlog.ErrProjectIDMustBeSet`, got: %v\", err)\n\t\t}\n\t})\n\n\tt.Run(\"returns request logs and related response logs\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tpath := t.TempDir() + \"bolt.db\"\n\t\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t\t}\n\n\t\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t\t}\n\t\tdefer db.Close()\n\n\t\tprojectID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\n\t\terr = db.UpsertProject(context.Background(), proj.Project{\n\t\t\tID: projectID,\n\t\t})\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error upserting project: %v\", err)\n\t\t}\n\n\t\tfixtures := []reqlog.RequestLog{\n\t\t\t{\n\t\t\t\tID:        ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy),\n\t\t\t\tProjectID: projectID,\n\t\t\t\tURL:       mustParseURL(t, \"https://example.com/foobar\"),\n\t\t\t\tMethod:    http.MethodPost,\n\t\t\t\tProto:     \"HTTP/1.1\",\n\t\t\t\tHeader: http.Header{\n\t\t\t\t\t\"X-Foo\": []string{\"baz\"},\n\t\t\t\t},\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t\tResponse: &reqlog.ResponseLog{\n\t\t\t\t\tProto:      \"HTTP/1.1\",\n\t\t\t\t\tStatus:     \"200 OK\",\n\t\t\t\t\tStatusCode: 200,\n\t\t\t\t\tHeader: http.Header{\n\t\t\t\t\t\t\"X-Yolo\": []string{\"swag\"},\n\t\t\t\t\t},\n\t\t\t\t\tBody: []byte(\"bar\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tID:        ulid.MustNew(ulid.Timestamp(time.Now())+100, ulidEntropy),\n\t\t\t\tProjectID: projectID,\n\t\t\t\tURL:       mustParseURL(t, \"https://example.com/foo?bar=baz\"),\n\t\t\t\tMethod:    http.MethodGet,\n\t\t\t\tProto:     \"HTTP/1.1\",\n\t\t\t\tHeader: http.Header{\n\t\t\t\t\t\"X-Foo\": []string{\"baz\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\t// Store fixtures.\n\t\tfor _, reqLog := range fixtures {\n\t\t\terr = db.StoreRequestLog(context.Background(), reqLog)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"unexpected error creating request log fixture: %v\", err)\n\t\t\t}\n\t\t}\n\n\t\tfilter := reqlog.FindRequestsFilter{\n\t\t\tProjectID: projectID,\n\t\t}\n\n\t\tgot, err := db.FindRequestLogs(context.Background(), filter, nil)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error finding request logs: %v\", err)\n\t\t}\n\n\t\t// We expect the found request logs are *reversed*, e.g. newest first.\n\t\texp := make([]reqlog.RequestLog, len(fixtures))\n\t\tfor i, j := 0, len(fixtures)-1; i < j; i, j = i+1, j-1 {\n\t\t\texp[i], exp[j] = fixtures[j], fixtures[i]\n\t\t}\n\n\t\tif diff := cmp.Diff(exp, got); diff != \"\" {\n\t\t\tt.Fatalf(\"request logs not equal (-exp, +got):\\n%v\", diff)\n\t\t}\n\t})\n}\n\nfunc mustParseURL(t *testing.T, s string) *url.URL {\n\tt.Helper()\n\n\tu, err := url.Parse(s)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn u\n}\n"
  },
  {
    "path": "pkg/db/bolt/sender.go",
    "content": "package bolt\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/gob\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/oklog/ulid\"\n\tbolt \"go.etcd.io/bbolt\"\n\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n\t\"github.com/dstotijn/hetty/pkg/sender\"\n)\n\nvar ErrSenderRequestsBucketNotFound = errors.New(\"bolt: sender requests bucket not found\")\n\nvar senderReqsBucketName = []byte(\"sender_requests\")\n\nfunc senderReqsBucket(tx *bolt.Tx, projectID ulid.ULID) (*bolt.Bucket, error) {\n\tpb, err := projectBucket(tx, projectID[:])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tb := pb.Bucket(senderReqsBucketName)\n\tif b == nil {\n\t\treturn nil, ErrSenderRequestsBucketNotFound\n\t}\n\n\treturn b, nil\n}\n\nfunc (db *Database) StoreSenderRequest(ctx context.Context, req sender.Request) error {\n\tbuf := bytes.Buffer{}\n\n\terr := gob.NewEncoder(&buf).Encode(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bolt: failed to encode sender request: %w\", err)\n\t}\n\n\terr = db.bolt.Update(func(tx *bolt.Tx) error {\n\t\tsenderReqsBucket, err := senderReqsBucket(tx, req.ProjectID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get sender requests bucket: %w\", err)\n\t\t}\n\n\t\terr = senderReqsBucket.Put(req.ID[:], buf.Bytes())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to put sender request: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bolt: failed to commit transaction: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (db *Database) FindSenderRequestByID(ctx context.Context, projectID, senderReqID ulid.ULID) (req sender.Request, err error) {\n\tif projectID.Compare(ulid.ULID{}) == 0 {\n\t\treturn sender.Request{}, sender.ErrProjectIDMustBeSet\n\t}\n\n\terr = db.bolt.View(func(tx *bolt.Tx) error {\n\t\tsenderReqsBucket, err := senderReqsBucket(tx, projectID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get sender requests bucket: %w\", err)\n\t\t}\n\n\t\trawSenderReq := senderReqsBucket.Get(senderReqID[:])\n\t\tif rawSenderReq == nil {\n\t\t\treturn sender.ErrRequestNotFound\n\t\t}\n\n\t\terr = gob.NewDecoder(bytes.NewReader(rawSenderReq)).Decode(&req)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decode sender request: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn sender.Request{}, fmt.Errorf(\"bolt: failed to commit transaction: %w\", err)\n\t}\n\n\treturn req, nil\n}\n\nfunc (db *Database) FindSenderRequests(ctx context.Context, filter sender.FindRequestsFilter, scope *scope.Scope) (reqs []sender.Request, err error) {\n\tif filter.ProjectID.Compare(ulid.ULID{}) == 0 {\n\t\treturn nil, sender.ErrProjectIDMustBeSet\n\t}\n\n\ttx, err := db.bolt.Begin(false)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"bolt: failed to begin transaction: %w\", err)\n\t}\n\tdefer tx.Rollback()\n\n\tb, err := senderReqsBucket(tx, filter.ProjectID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get sender requests bucket: %w\", err)\n\t}\n\n\terr = b.ForEach(func(senderReqID, rawSenderReq []byte) error {\n\t\tvar req sender.Request\n\t\terr = gob.NewDecoder(bytes.NewReader(rawSenderReq)).Decode(&req)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decode sender request: %w\", err)\n\t\t}\n\n\t\tif filter.OnlyInScope {\n\t\t\tif !req.MatchScope(scope) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\t// Filter by search expression. TODO: Once pagination is introduced,\n\t\t// this filter logic should be done as items are retrieved.\n\t\tif filter.SearchExpr != nil {\n\t\t\tmatch, err := req.Matches(filter.SearchExpr)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\"bolt: failed to match search expression for sender request (id: %v): %w\",\n\t\t\t\t\tsenderReqID, err,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tif !match {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\treqs = append(reqs, req)\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"bolt: failed to commit transaction: %w\", err)\n\t}\n\n\t// Reverse items, so newest requests appear first.\n\tfor i, j := 0, len(reqs)-1; i < j; i, j = i+1, j-1 {\n\t\treqs[i], reqs[j] = reqs[j], reqs[i]\n\t}\n\n\treturn reqs, nil\n}\n\nfunc (db *Database) DeleteSenderRequests(ctx context.Context, projectID ulid.ULID) error {\n\terr := db.bolt.Update(func(tx *bolt.Tx) error {\n\t\tsenderReqsBucket, err := senderReqsBucket(tx, projectID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get sender requests bucket: %w\", err)\n\t\t}\n\n\t\terr = senderReqsBucket.DeleteBucket(senderReqsBucketName)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to delete sender requests bucket: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"bolt: failed to commit transaction: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/db/bolt/sender_test.go",
    "content": "package bolt_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/oklog/ulid\"\n\t\"go.etcd.io/bbolt\"\n\n\t\"github.com/dstotijn/hetty/pkg/db/bolt\"\n\t\"github.com/dstotijn/hetty/pkg/proj\"\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n\t\"github.com/dstotijn/hetty/pkg/sender\"\n)\n\nvar exampleURL = func() *url.URL {\n\tu, err := url.Parse(\"https://example.com/foobar\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn u\n}()\n\nfunc TestFindRequestByID(t *testing.T) {\n\tt.Parallel()\n\n\tpath := t.TempDir() + \"bolt.db\"\n\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t}\n\tdefer boltDB.Close()\n\n\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t}\n\tdefer db.Close()\n\n\tprojectID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\treqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\n\terr = db.UpsertProject(context.Background(), proj.Project{\n\t\tID: projectID,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error upserting project: %v\", err)\n\t}\n\n\t// See: https://go.dev/blog/subtests#cleaning-up-after-a-group-of-parallel-tests\n\tt.Run(\"group\", func(t *testing.T) {\n\t\tt.Run(\"sender request not found\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t_, err := db.FindSenderRequestByID(context.Background(), projectID, reqID)\n\t\t\tif !errors.Is(err, sender.ErrRequestNotFound) {\n\t\t\t\tt.Fatalf(\"expected `sender.ErrRequestNotFound`, got: %v\", err)\n\t\t\t}\n\t\t})\n\n\t\tt.Run(\"sender request found\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\texp := sender.Request{\n\t\t\t\tID:                 ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy),\n\t\t\t\tProjectID:          projectID,\n\t\t\t\tSourceRequestLogID: ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy),\n\n\t\t\t\tURL:    exampleURL,\n\t\t\t\tMethod: http.MethodGet,\n\t\t\t\tProto:  sender.HTTPProto20,\n\t\t\t\tHeader: http.Header{\n\t\t\t\t\t\"X-Foo\": []string{\"bar\"},\n\t\t\t\t},\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t\tResponse: &reqlog.ResponseLog{\n\t\t\t\t\tProto:      \"HTTP/2.0\",\n\t\t\t\t\tStatus:     \"200 OK\",\n\t\t\t\t\tStatusCode: 200,\n\t\t\t\t\tHeader: http.Header{\n\t\t\t\t\t\t\"X-Yolo\": []string{\"swag\"},\n\t\t\t\t\t},\n\t\t\t\t\tBody: []byte(\"bar\"),\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := db.StoreSenderRequest(context.Background(), exp)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"unexpected error (expected: nil, got: %v)\", err)\n\t\t\t}\n\n\t\t\tgot, err := db.FindSenderRequestByID(context.Background(), exp.ProjectID, exp.ID)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"unexpected error (expected: nil, got: %v)\", err)\n\t\t\t}\n\n\t\t\tif diff := cmp.Diff(exp, got); diff != \"\" {\n\t\t\t\tt.Fatalf(\"sender request not equal (-exp, +got):\\n%v\", diff)\n\t\t\t}\n\t\t})\n\t})\n}\n\nfunc TestFindSenderRequests(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"without project ID in filter\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tpath := t.TempDir() + \"bolt.db\"\n\t\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t\t}\n\t\tdefer boltDB.Close()\n\n\t\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t\t}\n\t\tdefer db.Close()\n\n\t\tfilter := sender.FindRequestsFilter{}\n\n\t\t_, err = db.FindSenderRequests(context.Background(), filter, nil)\n\t\tif !errors.Is(err, sender.ErrProjectIDMustBeSet) {\n\t\t\tt.Fatalf(\"expected `sender.ErrProjectIDMustBeSet`, got: %v\", err)\n\t\t}\n\t})\n\n\tt.Run(\"returns sender requests and related response logs\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tpath := t.TempDir() + \"bolt.db\"\n\t\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t\t}\n\t\tdefer boltDB.Close()\n\n\t\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t\t}\n\t\tdefer db.Close()\n\n\t\tprojectID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\n\t\terr = db.UpsertProject(context.Background(), proj.Project{\n\t\t\tID:       projectID,\n\t\t\tName:     \"foobar\",\n\t\t\tSettings: proj.Settings{},\n\t\t})\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error creating project (expected: nil, got: %v)\", err)\n\t\t}\n\n\t\tfixtures := []sender.Request{\n\t\t\t{\n\t\t\t\tID:                 ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy),\n\t\t\t\tProjectID:          projectID,\n\t\t\t\tSourceRequestLogID: ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy),\n\t\t\t\tURL:                exampleURL,\n\t\t\t\tMethod:             http.MethodPost,\n\t\t\t\tProto:              \"HTTP/1.1\",\n\t\t\t\tHeader: http.Header{\n\t\t\t\t\t\"X-Foo\": []string{\"baz\"},\n\t\t\t\t},\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t\tResponse: &reqlog.ResponseLog{\n\t\t\t\t\tProto:      \"HTTP/1.1\",\n\t\t\t\t\tStatus:     \"200 OK\",\n\t\t\t\t\tStatusCode: 200,\n\t\t\t\t\tHeader: http.Header{\n\t\t\t\t\t\t\"X-Yolo\": []string{\"swag\"},\n\t\t\t\t\t},\n\t\t\t\t\tBody: []byte(\"bar\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tID:                 ulid.MustNew(ulid.Timestamp(time.Now())+100, ulidEntropy),\n\t\t\t\tProjectID:          projectID,\n\t\t\t\tSourceRequestLogID: ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy),\n\t\t\t\tURL:                exampleURL,\n\t\t\t\tMethod:             http.MethodGet,\n\t\t\t\tProto:              \"HTTP/1.1\",\n\t\t\t\tHeader: http.Header{\n\t\t\t\t\t\"X-Foo\": []string{\"baz\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\t// Store fixtures.\n\t\tfor _, senderReq := range fixtures {\n\t\t\terr = db.StoreSenderRequest(context.Background(), senderReq)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"unexpected error creating request log fixture: %v\", err)\n\t\t\t}\n\t\t}\n\n\t\tfilter := sender.FindRequestsFilter{\n\t\t\tProjectID: projectID,\n\t\t}\n\n\t\tgot, err := db.FindSenderRequests(context.Background(), filter, nil)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error finding sender requests: %v\", err)\n\t\t}\n\n\t\t// We expect the found sender requests are *reversed*, e.g. newest first.\n\t\texp := make([]sender.Request, len(fixtures))\n\t\tfor i, j := 0, len(fixtures)-1; i < j; i, j = i+1, j-1 {\n\t\t\texp[i], exp[j] = fixtures[j], fixtures[i]\n\t\t}\n\n\t\tif diff := cmp.Diff(exp, got); diff != \"\" {\n\t\t\tt.Fatalf(\"sender requests not equal (-exp, +got):\\n%v\", diff)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "pkg/filter/ast.go",
    "content": "package filter\n\nimport (\n\t\"encoding/gob\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype Expression interface {\n\tString() string\n}\n\ntype PrefixExpression struct {\n\tOperator TokenType\n\tRight    Expression\n}\n\nfunc (pe PrefixExpression) String() string {\n\tb := strings.Builder{}\n\tb.WriteString(\"(\")\n\tb.WriteString(pe.Operator.String())\n\tb.WriteString(\" \")\n\tb.WriteString(pe.Right.String())\n\tb.WriteString(\")\")\n\n\treturn b.String()\n}\n\ntype InfixExpression struct {\n\tOperator TokenType\n\tLeft     Expression\n\tRight    Expression\n}\n\nfunc (ie InfixExpression) String() string {\n\tb := strings.Builder{}\n\tb.WriteString(\"(\")\n\tb.WriteString(ie.Left.String())\n\tb.WriteString(\" \")\n\tb.WriteString(ie.Operator.String())\n\tb.WriteString(\" \")\n\tb.WriteString(ie.Right.String())\n\tb.WriteString(\")\")\n\n\treturn b.String()\n}\n\ntype StringLiteral struct {\n\tValue string\n}\n\nfunc (sl StringLiteral) String() string {\n\treturn strconv.Quote(sl.Value)\n}\n\ntype RegexpLiteral struct {\n\t*regexp.Regexp\n}\n\nfunc (rl RegexpLiteral) String() string {\n\treturn strconv.Quote(rl.Regexp.String())\n}\n\nfunc (rl RegexpLiteral) MarshalBinary() ([]byte, error) {\n\treturn []byte(rl.Regexp.String()), nil\n}\n\nfunc (rl *RegexpLiteral) UnmarshalBinary(data []byte) error {\n\tre, err := regexp.Compile(string(data))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*rl = RegexpLiteral{re}\n\n\treturn nil\n}\n\nfunc init() {\n\t// The `filter` package was previously named `search`.\n\t// We use the legacy names for backwards compatibility with existing database data.\n\tgob.RegisterName(\"github.com/dstotijn/hetty/pkg/search.PrefixExpression\", PrefixExpression{})\n\tgob.RegisterName(\"github.com/dstotijn/hetty/pkg/search.InfixExpression\", InfixExpression{})\n\tgob.RegisterName(\"github.com/dstotijn/hetty/pkg/search.StringLiteral\", StringLiteral{})\n\tgob.RegisterName(\"github.com/dstotijn/hetty/pkg/search.RegexpLiteral\", RegexpLiteral{})\n}\n"
  },
  {
    "path": "pkg/filter/ast_test.go",
    "content": "package filter_test\n\nimport (\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n)\n\nfunc TestExpressionString(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname       string\n\t\texpression filter.Expression\n\t\texpected   string\n\t}{\n\t\t{\n\t\t\tname:       \"string literal expression\",\n\t\t\texpression: filter.StringLiteral{Value: \"foobar\"},\n\t\t\texpected:   `\"foobar\"`,\n\t\t},\n\t\t{\n\t\t\tname: \"boolean expression with equal operator\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpEq,\n\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    filter.StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpected: `(\"foo\" = \"bar\")`,\n\t\t},\n\t\t{\n\t\t\tname: \"boolean expression with not equal operator\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpNotEq,\n\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    filter.StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpected: `(\"foo\" != \"bar\")`,\n\t\t},\n\t\t{\n\t\t\tname: \"boolean expression with greater than operator\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpGt,\n\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    filter.StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpected: `(\"foo\" > \"bar\")`,\n\t\t},\n\t\t{\n\t\t\tname: \"boolean expression with less than operator\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpLt,\n\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    filter.StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpected: `(\"foo\" < \"bar\")`,\n\t\t},\n\t\t{\n\t\t\tname: \"boolean expression with greater than or equal operator\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpGtEq,\n\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    filter.StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpected: `(\"foo\" >= \"bar\")`,\n\t\t},\n\t\t{\n\t\t\tname: \"boolean expression with less than or equal operator\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpLtEq,\n\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    filter.StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpected: `(\"foo\" <= \"bar\")`,\n\t\t},\n\t\t{\n\t\t\tname: \"boolean expression with regular expression operator\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpRe,\n\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    filter.RegexpLiteral{regexp.MustCompile(\"bar\")},\n\t\t\t},\n\t\t\texpected: `(\"foo\" =~ \"bar\")`,\n\t\t},\n\t\t{\n\t\t\tname: \"boolean expression with not regular expression operator\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpNotRe,\n\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    filter.RegexpLiteral{regexp.MustCompile(\"bar\")},\n\t\t\t},\n\t\t\texpected: `(\"foo\" !~ \"bar\")`,\n\t\t},\n\t\t{\n\t\t\tname: \"boolean expression with AND, OR and NOT operators\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpAnd,\n\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\tRight: filter.InfixExpression{\n\t\t\t\t\tOperator: filter.TokOpOr,\n\t\t\t\t\tLeft:     filter.StringLiteral{Value: \"bar\"},\n\t\t\t\t\tRight: filter.PrefixExpression{\n\t\t\t\t\t\tOperator: filter.TokOpNot,\n\t\t\t\t\t\tRight:    filter.StringLiteral{Value: \"baz\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: `(\"foo\" AND (\"bar\" OR (NOT \"baz\")))`,\n\t\t},\n\t\t{\n\t\t\tname: \"boolean expression with nested group\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpOr,\n\t\t\t\tLeft: filter.InfixExpression{\n\t\t\t\t\tOperator: filter.TokOpAnd,\n\t\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\t\tRight:    filter.StringLiteral{Value: \"bar\"},\n\t\t\t\t},\n\t\t\t\tRight: filter.PrefixExpression{\n\t\t\t\t\tOperator: filter.TokOpNot,\n\t\t\t\t\tRight:    filter.StringLiteral{Value: \"baz\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: `((\"foo\" AND \"bar\") OR (NOT \"baz\"))`,\n\t\t},\n\t\t{\n\t\t\tname: \"implicit boolean expression with string literal operands\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpAnd,\n\t\t\t\tLeft: filter.InfixExpression{\n\t\t\t\t\tOperator: filter.TokOpAnd,\n\t\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\t\tRight:    filter.StringLiteral{Value: \"bar\"},\n\t\t\t\t},\n\t\t\t\tRight: filter.StringLiteral{Value: \"baz\"},\n\t\t\t},\n\t\t\texpected: `((\"foo\" AND \"bar\") AND \"baz\")`,\n\t\t},\n\t\t{\n\t\t\tname: \"implicit boolean expression nested in group\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpAnd,\n\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    filter.StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpected: `(\"foo\" AND \"bar\")`,\n\t\t},\n\t\t{\n\t\t\tname: \"implicit and explicit boolean expression with string literal operands\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpAnd,\n\t\t\t\tLeft: filter.InfixExpression{\n\t\t\t\t\tOperator: filter.TokOpAnd,\n\t\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\t\tRight: filter.InfixExpression{\n\t\t\t\t\t\tOperator: filter.TokOpOr,\n\t\t\t\t\t\tLeft:     filter.StringLiteral{Value: \"bar\"},\n\t\t\t\t\t\tRight:    filter.StringLiteral{Value: \"baz\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tRight: filter.StringLiteral{Value: \"yolo\"},\n\t\t\t},\n\t\t\texpected: `((\"foo\" AND (\"bar\" OR \"baz\")) AND \"yolo\")`,\n\t\t},\n\t\t{\n\t\t\tname: \"implicit boolean expression with comparison operands\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpAnd,\n\t\t\t\tLeft: filter.InfixExpression{\n\t\t\t\t\tOperator: filter.TokOpEq,\n\t\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\t\tRight:    filter.StringLiteral{Value: \"bar\"},\n\t\t\t\t},\n\t\t\t\tRight: filter.InfixExpression{\n\t\t\t\t\tOperator: filter.TokOpRe,\n\t\t\t\t\tLeft:     filter.StringLiteral{Value: \"baz\"},\n\t\t\t\t\tRight:    filter.RegexpLiteral{regexp.MustCompile(\"yolo\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: `((\"foo\" = \"bar\") AND (\"baz\" =~ \"yolo\"))`,\n\t\t},\n\t\t{\n\t\t\tname: \"eq operator takes precedence over boolean ops\",\n\t\t\texpression: filter.InfixExpression{\n\t\t\t\tOperator: filter.TokOpOr,\n\t\t\t\tLeft: filter.InfixExpression{\n\t\t\t\t\tOperator: filter.TokOpEq,\n\t\t\t\t\tLeft:     filter.StringLiteral{Value: \"foo\"},\n\t\t\t\t\tRight:    filter.StringLiteral{Value: \"bar\"},\n\t\t\t\t},\n\t\t\t\tRight: filter.InfixExpression{\n\t\t\t\t\tOperator: filter.TokOpEq,\n\t\t\t\t\tLeft:     filter.StringLiteral{Value: \"baz\"},\n\t\t\t\t\tRight:    filter.StringLiteral{Value: \"yolo\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: `((\"foo\" = \"bar\") OR (\"baz\" = \"yolo\"))`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\ttt := tt\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tgot := tt.expression.String()\n\t\t\tif tt.expected != got {\n\t\t\t\tt.Errorf(\"expected: %v, got: %v\", tt.expected, got)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/filter/http.go",
    "content": "package filter\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc MatchHTTPHeaders(op TokenType, expr Expression, headers http.Header) (bool, error) {\n\tif headers == nil {\n\t\treturn false, nil\n\t}\n\n\tswitch op {\n\tcase TokOpEq:\n\t\tstrLiteral, ok := expr.(StringLiteral)\n\t\tif !ok {\n\t\t\treturn false, errors.New(\"filter: expression must be a string literal\")\n\t\t}\n\n\t\t// Return `true` if at least one header (<key>: <value>) is equal to the string literal.\n\t\tfor key, values := range headers {\n\t\t\tfor _, value := range values {\n\t\t\t\tif strLiteral.Value == fmt.Sprintf(\"%v: %v\", key, value) {\n\t\t\t\t\treturn true, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false, nil\n\tcase TokOpNotEq:\n\t\tstrLiteral, ok := expr.(StringLiteral)\n\t\tif !ok {\n\t\t\treturn false, errors.New(\"filter: expression must be a string literal\")\n\t\t}\n\n\t\t// Return `true` if none of the headers (<key>: <value>) are equal to the string literal.\n\t\tfor key, values := range headers {\n\t\t\tfor _, value := range values {\n\t\t\t\tif strLiteral.Value == fmt.Sprintf(\"%v: %v\", key, value) {\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true, nil\n\tcase TokOpRe:\n\t\tre, ok := expr.(RegexpLiteral)\n\t\tif !ok {\n\t\t\treturn false, errors.New(\"filter: expression must be a regular expression\")\n\t\t}\n\n\t\t// Return `true` if at least one header (<key>: <value>) matches the regular expression.\n\t\tfor key, values := range headers {\n\t\t\tfor _, value := range values {\n\t\t\t\tif re.MatchString(fmt.Sprintf(\"%v: %v\", key, value)) {\n\t\t\t\t\treturn true, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false, nil\n\tcase TokOpNotRe:\n\t\tre, ok := expr.(RegexpLiteral)\n\t\tif !ok {\n\t\t\treturn false, errors.New(\"filter: expression must be a regular expression\")\n\t\t}\n\n\t\t// Return `true` if none of the headers (<key>: <value>) match the regular expression.\n\t\tfor key, values := range headers {\n\t\t\tfor _, value := range values {\n\t\t\t\tif re.MatchString(fmt.Sprintf(\"%v: %v\", key, value)) {\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true, nil\n\tdefault:\n\t\treturn false, fmt.Errorf(\"filter: unsupported operator %q\", op.String())\n\t}\n}\n"
  },
  {
    "path": "pkg/filter/lexer.go",
    "content": "package filter\n\nimport (\n\t\"fmt\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\ntype TokenType int\n\ntype Token struct {\n\tType    TokenType\n\tLiteral string\n}\n\nconst eof = 0\n\n// Token types.\nconst (\n\t// Flow.\n\tTokInvalid TokenType = iota\n\tTokEOF\n\tTokParenOpen\n\tTokParenClose\n\n\t// Literals.\n\tTokString\n\n\t// Boolean operators.\n\tTokOpNot\n\tTokOpAnd\n\tTokOpOr\n\n\t// Comparison operators.\n\tTokOpEq\n\tTokOpNotEq\n\tTokOpGt\n\tTokOpLt\n\tTokOpGtEq\n\tTokOpLtEq\n\tTokOpRe\n\tTokOpNotRe\n)\n\nvar (\n\tkeywords = map[string]TokenType{\n\t\t\"NOT\": TokOpNot,\n\t\t\"AND\": TokOpAnd,\n\t\t\"OR\":  TokOpOr,\n\t}\n\treservedRunes    = []rune{'=', '!', '<', '>', '(', ')'}\n\ttokenTypeStrings = map[TokenType]string{\n\t\tTokInvalid:    \"INVALID\",\n\t\tTokEOF:        \"EOF\",\n\t\tTokParenOpen:  \"(\",\n\t\tTokParenClose: \")\",\n\t\tTokString:     \"STRING\",\n\t\tTokOpNot:      \"NOT\",\n\t\tTokOpAnd:      \"AND\",\n\t\tTokOpOr:       \"OR\",\n\t\tTokOpEq:       \"=\",\n\t\tTokOpNotEq:    \"!=\",\n\t\tTokOpGt:       \">\",\n\t\tTokOpLt:       \"<\",\n\t\tTokOpGtEq:     \">=\",\n\t\tTokOpLtEq:     \"<=\",\n\t\tTokOpRe:       \"=~\",\n\t\tTokOpNotRe:    \"!~\",\n\t}\n)\n\ntype stateFn func(*Lexer) stateFn\n\ntype Lexer struct {\n\tinput  string\n\tpos    int\n\tstart  int\n\twidth  int\n\ttokens chan Token\n}\n\nfunc NewLexer(input string) *Lexer {\n\tl := &Lexer{\n\t\tinput:  input,\n\t\ttokens: make(chan Token),\n\t}\n\n\tgo l.run(begin)\n\n\treturn l\n}\n\nfunc (l *Lexer) Next() Token {\n\treturn <-l.tokens\n}\n\nfunc (tt TokenType) String() string {\n\tif typeString, ok := tokenTypeStrings[tt]; ok {\n\t\treturn typeString\n\t}\n\n\treturn \"<unknown>\"\n}\n\nfunc (l *Lexer) run(init stateFn) {\n\tfor nextState := init; nextState != nil; {\n\t\tnextState = nextState(l)\n\t}\n\tclose(l.tokens)\n}\n\nfunc (l *Lexer) read() (r rune) {\n\tif l.pos >= len(l.input) {\n\t\tl.width = 0\n\t\treturn eof\n\t}\n\n\tr, l.width = utf8.DecodeRuneInString(l.input[l.pos:])\n\tl.pos += l.width\n\n\treturn\n}\n\nfunc (l *Lexer) emit(tokenType TokenType) {\n\tl.tokens <- Token{\n\t\tType:    tokenType,\n\t\tLiteral: l.input[l.start:l.pos],\n\t}\n\n\tl.start = l.pos\n}\n\nfunc (l *Lexer) ignore() {\n\tl.start = l.pos\n}\n\nfunc (l *Lexer) skip() {\n\tl.pos += l.width\n\tl.start = l.pos\n}\n\nfunc (l *Lexer) backup() {\n\tl.pos -= l.width\n}\n\nfunc (l *Lexer) errorf(format string, args ...interface{}) stateFn {\n\tl.tokens <- Token{\n\t\tType:    TokInvalid,\n\t\tLiteral: fmt.Sprintf(format, args...),\n\t}\n\n\treturn nil\n}\n\nfunc begin(l *Lexer) stateFn {\n\tr := l.read()\n\tswitch r {\n\tcase '=':\n\t\tif next := l.read(); next == '~' {\n\t\t\tl.emit(TokOpRe)\n\t\t} else {\n\t\t\tl.backup()\n\t\t\tl.emit(TokOpEq)\n\t\t}\n\n\t\treturn begin\n\tcase '!':\n\t\tswitch next := l.read(); next {\n\t\tcase '=':\n\t\t\tl.emit(TokOpNotEq)\n\t\tcase '~':\n\t\t\tl.emit(TokOpNotRe)\n\t\tdefault:\n\t\t\treturn l.errorf(\"invalid rune %v\", r)\n\t\t}\n\n\t\treturn begin\n\tcase '<':\n\t\tif next := l.read(); next == '=' {\n\t\t\tl.emit(TokOpLtEq)\n\t\t} else {\n\t\t\tl.backup()\n\t\t\tl.emit(TokOpLt)\n\t\t}\n\n\t\treturn begin\n\tcase '>':\n\t\tif next := l.read(); next == '=' {\n\t\t\tl.emit(TokOpGtEq)\n\t\t} else {\n\t\t\tl.backup()\n\t\t\tl.emit(TokOpGt)\n\t\t}\n\n\t\treturn begin\n\tcase '(':\n\t\tl.emit(TokParenOpen)\n\t\treturn begin\n\tcase ')':\n\t\tl.emit(TokParenClose)\n\t\treturn begin\n\tcase '\"':\n\t\treturn l.delimString(r)\n\tcase eof:\n\t\tl.emit(TokEOF)\n\t\treturn nil\n\t}\n\n\tif unicode.IsSpace(r) {\n\t\tl.ignore()\n\t\treturn begin\n\t}\n\n\treturn unquotedString\n}\n\nfunc (l *Lexer) delimString(delim rune) stateFn {\n\t// Ignore the start delimiter rune.\n\tl.ignore()\n\n\tfor r := l.read(); r != delim; r = l.read() {\n\t\tif r == eof {\n\t\t\treturn l.errorf(\"unexpected EOF, unclosed delimiter\")\n\t\t}\n\t}\n\t// Don't include the end delimiter in emitted token.\n\tl.backup()\n\tl.emit(TokString)\n\t// Skip end delimiter.\n\tl.skip()\n\n\treturn begin\n}\n\nfunc unquotedString(l *Lexer) stateFn {\n\tfor r := l.read(); ; r = l.read() {\n\t\tswitch {\n\t\tcase r == eof:\n\t\t\tl.backup()\n\t\t\tl.emitUnquotedString()\n\n\t\t\treturn begin\n\t\tcase unicode.IsSpace(r):\n\t\t\tl.backup()\n\t\t\tl.emitUnquotedString()\n\t\t\tl.skip()\n\n\t\t\treturn begin\n\t\tcase isReserved(r):\n\t\t\tl.backup()\n\t\t\tl.emitUnquotedString()\n\n\t\t\treturn begin\n\t\t}\n\t}\n}\n\nfunc (l *Lexer) emitUnquotedString() {\n\tstr := l.input[l.start:l.pos]\n\tif tokType, ok := keywords[str]; ok {\n\t\tl.emit(tokType)\n\t\treturn\n\t}\n\n\tl.emit(TokString)\n}\n\nfunc isReserved(r rune) bool {\n\tfor _, v := range reservedRunes {\n\t\tif r == v {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "pkg/filter/lexer_test.go",
    "content": "package filter\n\nimport \"testing\"\n\nfunc TestNextToken(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected []Token\n\t}{\n\t\t{\n\t\t\tname:  \"unquoted string\",\n\t\t\tinput: \"foo bar\",\n\t\t\texpected: []Token{\n\t\t\t\t{TokString, \"foo\"},\n\t\t\t\t{TokString, \"bar\"},\n\t\t\t\t{TokEOF, \"\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"quoted string\",\n\t\t\tinput: `\"foo bar\" \"baz\"`,\n\t\t\texpected: []Token{\n\t\t\t\t{TokString, \"foo bar\"},\n\t\t\t\t{TokString, \"baz\"},\n\t\t\t\t{TokEOF, \"\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"boolean operator token types\",\n\t\t\tinput: \"NOT AND OR\",\n\t\t\texpected: []Token{\n\t\t\t\t{TokOpNot, \"NOT\"},\n\t\t\t\t{TokOpAnd, \"AND\"},\n\t\t\t\t{TokOpOr, \"OR\"},\n\t\t\t\t{TokEOF, \"\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"comparison operator token types\",\n\t\t\tinput: `= != < > <= >= =~ !~`,\n\t\t\texpected: []Token{\n\t\t\t\t{TokOpEq, \"=\"},\n\t\t\t\t{TokOpNotEq, \"!=\"},\n\t\t\t\t{TokOpLt, \"<\"},\n\t\t\t\t{TokOpGt, \">\"},\n\t\t\t\t{TokOpLtEq, \"<=\"},\n\t\t\t\t{TokOpGtEq, \">=\"},\n\t\t\t\t{TokOpRe, \"=~\"},\n\t\t\t\t{TokOpNotRe, \"!~\"},\n\t\t\t\t{TokEOF, \"\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"with parentheses\",\n\t\t\tinput: \"(foo AND bar) OR baz\",\n\t\t\texpected: []Token{\n\t\t\t\t{TokParenOpen, \"(\"},\n\t\t\t\t{TokString, \"foo\"},\n\t\t\t\t{TokOpAnd, \"AND\"},\n\t\t\t\t{TokString, \"bar\"},\n\t\t\t\t{TokParenClose, \")\"},\n\t\t\t\t{TokOpOr, \"OR\"},\n\t\t\t\t{TokString, \"baz\"},\n\t\t\t\t{TokEOF, \"\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor i, tt := range tests {\n\t\ttt := tt\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tl := NewLexer(tt.input)\n\n\t\t\tfor _, exp := range tt.expected {\n\t\t\t\tgot := l.Next()\n\t\t\t\tif got.Type != exp.Type {\n\t\t\t\t\tt.Errorf(\"invalid type (idx: %v, expected: %v, got: %v)\",\n\t\t\t\t\t\ti, exp.Type, got.Type)\n\t\t\t\t}\n\t\t\t\tif got.Literal != exp.Literal {\n\t\t\t\t\tt.Errorf(\"invalid literal (idx: %v, expected: %v, got: %v)\",\n\t\t\t\t\t\ti, exp.Literal, got.Literal)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/filter/parser.go",
    "content": "package filter\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n)\n\ntype precedence int\n\nconst (\n\t_ precedence = iota\n\tprecLowest\n\tprecAnd\n\tprecOr\n\tprecNot\n\tprecEq\n\tprecLessGreater\n\tprecPrefix\n\tprecGroup\n)\n\ntype (\n\tprefixParser func(*Parser) (Expression, error)\n\tinfixParser  func(*Parser, Expression) (Expression, error)\n)\n\nvar (\n\tprefixParsers = map[TokenType]prefixParser{}\n\tinfixParsers  = map[TokenType]infixParser{}\n)\n\nvar tokenPrecedences = map[TokenType]precedence{\n\tTokParenOpen: precGroup,\n\tTokOpNot:     precNot,\n\tTokOpAnd:     precAnd,\n\tTokOpOr:      precOr,\n\tTokOpEq:      precEq,\n\tTokOpNotEq:   precEq,\n\tTokOpGt:      precLessGreater,\n\tTokOpLt:      precLessGreater,\n\tTokOpGtEq:    precLessGreater,\n\tTokOpLtEq:    precLessGreater,\n\tTokOpRe:      precEq,\n\tTokOpNotRe:   precEq,\n}\n\nfunc init() {\n\t// Populate maps in `init`, because package global variables would cause an\n\t// initialization cycle.\n\tinfixOperators := []TokenType{\n\t\tTokOpAnd,\n\t\tTokOpOr,\n\t\tTokOpEq,\n\t\tTokOpNotEq,\n\t\tTokOpGt,\n\t\tTokOpLt,\n\t\tTokOpGtEq,\n\t\tTokOpLtEq,\n\t\tTokOpRe,\n\t\tTokOpNotRe,\n\t}\n\tfor _, op := range infixOperators {\n\t\tinfixParsers[op] = parseInfixExpression\n\t}\n\n\tprefixParsers[TokOpNot] = parsePrefixExpression\n\tprefixParsers[TokString] = parseStringLiteral\n\tprefixParsers[TokParenOpen] = parseGroupedExpression\n}\n\ntype Parser struct {\n\tl    *Lexer\n\tcur  Token\n\tpeek Token\n}\n\nfunc NewParser(l *Lexer) *Parser {\n\tp := &Parser{l: l}\n\tp.nextToken()\n\tp.nextToken()\n\n\treturn p\n}\n\nfunc ParseQuery(input string) (expr Expression, err error) {\n\tp := &Parser{l: NewLexer(input)}\n\tp.nextToken()\n\tp.nextToken()\n\n\tif p.curTokenIs(TokEOF) {\n\t\treturn nil, fmt.Errorf(\"filter: unexpected EOF\")\n\t}\n\n\tfor !p.curTokenIs(TokEOF) {\n\t\tright, err := p.parseExpression(precLowest)\n\n\t\tswitch {\n\t\tcase err != nil:\n\t\t\treturn nil, fmt.Errorf(\"filter: could not parse expression: %w\", err)\n\t\tcase expr == nil:\n\t\t\texpr = right\n\t\tdefault:\n\t\t\texpr = InfixExpression{\n\t\t\t\tOperator: TokOpAnd,\n\t\t\t\tLeft:     expr,\n\t\t\t\tRight:    right,\n\t\t\t}\n\t\t}\n\n\t\tp.nextToken()\n\t}\n\n\treturn\n}\n\nfunc (p *Parser) nextToken() {\n\tp.cur = p.peek\n\tp.peek = p.l.Next()\n}\n\nfunc (p *Parser) curTokenIs(t TokenType) bool {\n\treturn p.cur.Type == t\n}\n\nfunc (p *Parser) peekTokenIs(t TokenType) bool {\n\treturn p.peek.Type == t\n}\n\nfunc (p *Parser) curPrecedence() precedence {\n\tif p, ok := tokenPrecedences[p.cur.Type]; ok {\n\t\treturn p\n\t}\n\n\treturn precLowest\n}\n\nfunc (p *Parser) peekPrecedence() precedence {\n\tif p, ok := tokenPrecedences[p.peek.Type]; ok {\n\t\treturn p\n\t}\n\n\treturn precLowest\n}\n\nfunc (p *Parser) parseExpression(prec precedence) (Expression, error) {\n\tprefixParser, ok := prefixParsers[p.cur.Type]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"no prefix parse function for %v found\", p.cur.Type)\n\t}\n\n\texpr, err := prefixParser(p)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not parse expression prefix: %w\", err)\n\t}\n\n\tfor !p.peekTokenIs(eof) && prec < p.peekPrecedence() {\n\t\tinfixParser, ok := infixParsers[p.peek.Type]\n\t\tif !ok {\n\t\t\tbreak\n\t\t}\n\n\t\tp.nextToken()\n\n\t\texpr, err = infixParser(p, expr)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not parse infix expression: %w\", err)\n\t\t}\n\t}\n\n\treturn expr, nil\n}\n\nfunc parsePrefixExpression(p *Parser) (Expression, error) {\n\texpr := PrefixExpression{\n\t\tOperator: p.cur.Type,\n\t}\n\n\tp.nextToken()\n\n\tright, err := p.parseExpression(precPrefix)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not parse expression for right operand: %w\", err)\n\t}\n\n\texpr.Right = right\n\n\treturn expr, nil\n}\n\nfunc parseInfixExpression(p *Parser, left Expression) (Expression, error) {\n\texpr := InfixExpression{\n\t\tOperator: p.cur.Type,\n\t\tLeft:     left,\n\t}\n\n\tprec := p.curPrecedence()\n\tp.nextToken()\n\n\tright, err := p.parseExpression(prec)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not parse expression for right operand: %w\", err)\n\t}\n\n\tif expr.Operator == TokOpRe || expr.Operator == TokOpNotRe {\n\t\tif rightStr, ok := right.(StringLiteral); ok {\n\t\t\tre, err := regexp.Compile(rightStr.Value)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"could not compile regular expression %q: %w\", rightStr.Value, err)\n\t\t\t}\n\n\t\t\tright = RegexpLiteral{re}\n\t\t}\n\t}\n\n\texpr.Right = right\n\n\treturn expr, nil\n}\n\nfunc parseStringLiteral(p *Parser) (Expression, error) {\n\treturn StringLiteral{Value: p.cur.Literal}, nil\n}\n\nfunc parseGroupedExpression(p *Parser) (Expression, error) {\n\tp.nextToken()\n\n\texpr, err := p.parseExpression(precLowest)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not parse grouped expression: %w\", err)\n\t}\n\n\tfor p.nextToken(); !p.curTokenIs(TokParenClose); p.nextToken() {\n\t\tif p.curTokenIs(TokEOF) {\n\t\t\treturn nil, fmt.Errorf(\"unexpected EOF: unmatched parentheses\")\n\t\t}\n\n\t\tright, err := p.parseExpression(precLowest)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not parse expression: %w\", err)\n\t\t}\n\n\t\texpr = InfixExpression{\n\t\t\tOperator: TokOpAnd,\n\t\t\tLeft:     expr,\n\t\t\tRight:    right,\n\t\t}\n\t}\n\n\treturn expr, nil\n}\n"
  },
  {
    "path": "pkg/filter/parser_test.go",
    "content": "package filter\n\nimport (\n\t\"errors\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"testing\"\n)\n\nfunc TestParseQuery(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname               string\n\t\tinput              string\n\t\texpectedExpression Expression\n\t\texpectedError      error\n\t}{\n\t\t{\n\t\t\tname:               \"empty query\",\n\t\t\tinput:              \"\",\n\t\t\texpectedExpression: nil,\n\t\t\texpectedError:      errors.New(\"filter: unexpected EOF\"),\n\t\t},\n\t\t{\n\t\t\tname:               \"string literal expression\",\n\t\t\tinput:              \"foobar\",\n\t\t\texpectedExpression: StringLiteral{Value: \"foobar\"},\n\t\t\texpectedError:      nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"boolean expression with equal operator\",\n\t\t\tinput: \"foo = bar\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpEq,\n\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"boolean expression with not equal operator\",\n\t\t\tinput: \"foo != bar\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpNotEq,\n\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"boolean expression with greater than operator\",\n\t\t\tinput: \"foo > bar\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpGt,\n\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"boolean expression with less than operator\",\n\t\t\tinput: \"foo < bar\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpLt,\n\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"boolean expression with greater than or equal operator\",\n\t\t\tinput: \"foo >= bar\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpGtEq,\n\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"boolean expression with less than or equal operator\",\n\t\t\tinput: \"foo <= bar\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpLtEq,\n\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"boolean expression with regular expression operator\",\n\t\t\tinput: \"foo =~ bar\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpRe,\n\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    RegexpLiteral{regexp.MustCompile(\"bar\")},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"boolean expression with not regular expression operator\",\n\t\t\tinput: \"foo !~ bar\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpNotRe,\n\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    RegexpLiteral{regexp.MustCompile(\"bar\")},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"boolean expression with AND, OR and NOT operators\",\n\t\t\tinput: \"foo AND bar OR NOT baz\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpAnd,\n\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\tRight: InfixExpression{\n\t\t\t\t\tOperator: TokOpOr,\n\t\t\t\t\tLeft:     StringLiteral{Value: \"bar\"},\n\t\t\t\t\tRight: PrefixExpression{\n\t\t\t\t\t\tOperator: TokOpNot,\n\t\t\t\t\t\tRight:    StringLiteral{Value: \"baz\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"boolean expression with nested group\",\n\t\t\tinput: \"(foo AND bar) OR NOT baz\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpOr,\n\t\t\t\tLeft: InfixExpression{\n\t\t\t\t\tOperator: TokOpAnd,\n\t\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\t\tRight:    StringLiteral{Value: \"bar\"},\n\t\t\t\t},\n\t\t\t\tRight: PrefixExpression{\n\t\t\t\t\tOperator: TokOpNot,\n\t\t\t\t\tRight:    StringLiteral{Value: \"baz\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"implicit boolean expression with string literal operands\",\n\t\t\tinput: \"foo bar baz\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpAnd,\n\t\t\t\tLeft: InfixExpression{\n\t\t\t\t\tOperator: TokOpAnd,\n\t\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\t\tRight:    StringLiteral{Value: \"bar\"},\n\t\t\t\t},\n\t\t\t\tRight: StringLiteral{Value: \"baz\"},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"implicit boolean expression nested in group\",\n\t\t\tinput: \"(foo bar)\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpAnd,\n\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\tRight:    StringLiteral{Value: \"bar\"},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"implicit and explicit boolean expression with string literal operands\",\n\t\t\tinput: \"foo bar OR baz yolo\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpAnd,\n\t\t\t\tLeft: InfixExpression{\n\t\t\t\t\tOperator: TokOpAnd,\n\t\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\t\tRight: InfixExpression{\n\t\t\t\t\t\tOperator: TokOpOr,\n\t\t\t\t\t\tLeft:     StringLiteral{Value: \"bar\"},\n\t\t\t\t\t\tRight:    StringLiteral{Value: \"baz\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tRight: StringLiteral{Value: \"yolo\"},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"implicit boolean expression with comparison operands\",\n\t\t\tinput: \"foo=bar baz=~yolo\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpAnd,\n\t\t\t\tLeft: InfixExpression{\n\t\t\t\t\tOperator: TokOpEq,\n\t\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\t\tRight:    StringLiteral{Value: \"bar\"},\n\t\t\t\t},\n\t\t\t\tRight: InfixExpression{\n\t\t\t\t\tOperator: TokOpRe,\n\t\t\t\t\tLeft:     StringLiteral{Value: \"baz\"},\n\t\t\t\t\tRight:    RegexpLiteral{regexp.MustCompile(\"yolo\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"eq operator takes precedence over boolean ops\",\n\t\t\tinput: \"foo=bar OR baz=yolo\",\n\t\t\texpectedExpression: InfixExpression{\n\t\t\t\tOperator: TokOpOr,\n\t\t\t\tLeft: InfixExpression{\n\t\t\t\t\tOperator: TokOpEq,\n\t\t\t\t\tLeft:     StringLiteral{Value: \"foo\"},\n\t\t\t\t\tRight:    StringLiteral{Value: \"bar\"},\n\t\t\t\t},\n\t\t\t\tRight: InfixExpression{\n\t\t\t\t\tOperator: TokOpEq,\n\t\t\t\t\tLeft:     StringLiteral{Value: \"baz\"},\n\t\t\t\t\tRight:    StringLiteral{Value: \"yolo\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\ttt := tt\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tgot, err := ParseQuery(tt.input)\n\t\t\tassertError(t, tt.expectedError, err)\n\t\t\tif !reflect.DeepEqual(tt.expectedExpression, got) {\n\t\t\t\tt.Errorf(\"expected: %v, got: %v\", tt.expectedExpression, got)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc assertError(t *testing.T, exp, got error) {\n\tt.Helper()\n\n\tswitch {\n\tcase exp == nil && got != nil:\n\t\tt.Fatalf(\"expected: nil, got: %v\", got)\n\tcase exp != nil && got == nil:\n\t\tt.Fatalf(\"expected: %v, got: nil\", exp.Error())\n\tcase exp != nil && got != nil && exp.Error() != got.Error():\n\t\tt.Fatalf(\"expected: %v, got: %v\", exp.Error(), got.Error())\n\t}\n}\n"
  },
  {
    "path": "pkg/log/log.go",
    "content": "package log\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zapcore\"\n)\n\ntype Logger interface {\n\tDebugw(msg string, v ...interface{})\n\tInfow(msg string, v ...interface{})\n\tErrorw(msg string, v ...interface{})\n}\n\nfunc NewZapLogger(verbose, jsonLogs bool) (*zap.Logger, error) {\n\tvar config zap.Config\n\n\tif verbose {\n\t\tconfig = zap.Config{\n\t\t\tLevel:       zap.NewAtomicLevelAt(zap.DebugLevel),\n\t\t\tDevelopment: true,\n\t\t\tEncoding:    \"json\",\n\t\t\tEncoderConfig: zapcore.EncoderConfig{\n\t\t\t\tTimeKey:        \"ts\",\n\t\t\t\tLevelKey:       \"level\",\n\t\t\t\tNameKey:        \"logger\",\n\t\t\t\tCallerKey:      \"caller\",\n\t\t\t\tFunctionKey:    zapcore.OmitKey,\n\t\t\t\tMessageKey:     \"message\",\n\t\t\t\tStacktraceKey:  \"stacktrace\",\n\t\t\t\tLineEnding:     zapcore.DefaultLineEnding,\n\t\t\t\tEncodeLevel:    zapcore.LowercaseLevelEncoder,\n\t\t\t\tEncodeTime:     zapcore.RFC3339TimeEncoder,\n\t\t\t\tEncodeDuration: zapcore.SecondsDurationEncoder,\n\t\t\t\tEncodeCaller:   zapcore.ShortCallerEncoder,\n\t\t\t},\n\t\t\tOutputPaths:      []string{\"stderr\"},\n\t\t\tErrorOutputPaths: []string{\"stderr\"},\n\t\t}\n\t} else {\n\t\tconfig = zap.NewProductionConfig()\n\t}\n\n\tif !jsonLogs {\n\t\tconfig.Encoding = \"console\"\n\t\tconfig.EncoderConfig = zapcore.EncoderConfig{\n\t\t\tTimeKey:          \"T\",\n\t\t\tLevelKey:         \"L\",\n\t\t\tNameKey:          \"N\",\n\t\t\tCallerKey:        zapcore.OmitKey,\n\t\t\tFunctionKey:      zapcore.OmitKey,\n\t\t\tMessageKey:       \"M\",\n\t\t\tStacktraceKey:    zapcore.OmitKey,\n\t\t\tConsoleSeparator: \" \",\n\t\t\tLineEnding:       zapcore.DefaultLineEnding,\n\t\t\tEncodeLevel:      zapcore.CapitalColorLevelEncoder,\n\t\t\tEncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {\n\t\t\t\tenc.AppendString(t.Format(\"2006/01/02 15:04:05\"))\n\t\t\t},\n\t\t\tEncodeName: func(loggerName string, enc zapcore.PrimitiveArrayEncoder) {\n\t\t\t\t// Print logger name in cyan (ANSI code 36).\n\t\t\t\tenc.AppendString(fmt.Sprintf(\"\\x1b[%dm%s\\x1b[0m\", uint8(36), \"[\"+loggerName+\"]\"))\n\t\t\t},\n\t\t\tEncodeDuration: zapcore.StringDurationEncoder,\n\t\t\tEncodeCaller:   zapcore.ShortCallerEncoder,\n\t\t}\n\n\t\tif verbose {\n\t\t\tconfig.EncoderConfig.CallerKey = \"C\"\n\t\t\tconfig.EncoderConfig.StacktraceKey = \"S\"\n\t\t}\n\t}\n\n\treturn config.Build()\n}\n\ntype NopLogger struct{}\n\nfunc (nop NopLogger) Debugw(_ string, _ ...interface{}) {}\nfunc (nop NopLogger) Infow(_ string, _ ...interface{})  {}\nfunc (nop NopLogger) Errorw(_ string, _ ...interface{}) {}\n\nfunc NewNopLogger() NopLogger {\n\treturn NopLogger{}\n}\n"
  },
  {
    "path": "pkg/proj/proj.go",
    "content": "package proj\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"regexp\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/oklog/ulid\"\n\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n\t\"github.com/dstotijn/hetty/pkg/proxy/intercept\"\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n\t\"github.com/dstotijn/hetty/pkg/sender\"\n)\n\n//nolint:gosec\nvar ulidEntropy = rand.New(rand.NewSource(time.Now().UnixNano()))\n\ntype Service struct {\n\trepo            Repository\n\tinterceptSvc    *intercept.Service\n\treqLogSvc       *reqlog.Service\n\tsenderSvc       *sender.Service\n\tscope           *scope.Scope\n\tactiveProjectID ulid.ULID\n\tmu              sync.RWMutex\n}\n\ntype Project struct {\n\tID       ulid.ULID\n\tName     string\n\tSettings Settings\n\n\tisActive bool\n}\n\ntype Settings struct {\n\t// Request log settings\n\tReqLogBypassOutOfScope bool\n\tReqLogOnlyFindInScope  bool\n\tReqLogSearchExpr       filter.Expression\n\n\t// Intercept settings\n\tInterceptRequests       bool\n\tInterceptResponses      bool\n\tInterceptRequestFilter  filter.Expression\n\tInterceptResponseFilter filter.Expression\n\n\t// Sender settings\n\tSenderOnlyFindInScope bool\n\tSenderSearchExpr      filter.Expression\n\n\t// Scope settings\n\tScopeRules []scope.Rule\n}\n\nvar (\n\tErrProjectNotFound = errors.New(\"proj: project not found\")\n\tErrNoProject       = errors.New(\"proj: no open project\")\n\tErrNoSettings      = errors.New(\"proj: settings not found\")\n\tErrInvalidName     = errors.New(\"proj: invalid name, must be alphanumeric or whitespace chars\")\n)\n\nvar nameRegexp = regexp.MustCompile(`^[\\w\\d\\s]+$`)\n\ntype Config struct {\n\tRepository       Repository\n\tInterceptService *intercept.Service\n\tReqLogService    *reqlog.Service\n\tSenderService    *sender.Service\n\tScope            *scope.Scope\n}\n\n// NewService returns a new Service.\nfunc NewService(cfg Config) (*Service, error) {\n\treturn &Service{\n\t\trepo:         cfg.Repository,\n\t\tinterceptSvc: cfg.InterceptService,\n\t\treqLogSvc:    cfg.ReqLogService,\n\t\tsenderSvc:    cfg.SenderService,\n\t\tscope:        cfg.Scope,\n\t}, nil\n}\n\nfunc (svc *Service) CreateProject(ctx context.Context, name string) (Project, error) {\n\tif !nameRegexp.MatchString(name) {\n\t\treturn Project{}, ErrInvalidName\n\t}\n\n\tproject := Project{\n\t\tID:   ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy),\n\t\tName: name,\n\t}\n\n\terr := svc.repo.UpsertProject(ctx, project)\n\tif err != nil {\n\t\treturn Project{}, fmt.Errorf(\"proj: could not create project: %w\", err)\n\t}\n\n\treturn project, nil\n}\n\n// CloseProject closes the currently open project (if there is one).\nfunc (svc *Service) CloseProject() error {\n\tsvc.mu.Lock()\n\tdefer svc.mu.Unlock()\n\n\tif svc.activeProjectID.Compare(ulid.ULID{}) == 0 {\n\t\treturn nil\n\t}\n\n\tsvc.activeProjectID = ulid.ULID{}\n\tsvc.reqLogSvc.SetActiveProjectID(ulid.ULID{})\n\tsvc.reqLogSvc.SetBypassOutOfScopeRequests(false)\n\tsvc.reqLogSvc.SetFindReqsFilter(reqlog.FindRequestsFilter{})\n\tsvc.interceptSvc.UpdateSettings(intercept.Settings{\n\t\tRequestsEnabled:  false,\n\t\tResponsesEnabled: false,\n\t\tRequestFilter:    nil,\n\t\tResponseFilter:   nil,\n\t})\n\tsvc.senderSvc.SetActiveProjectID(ulid.ULID{})\n\tsvc.senderSvc.SetFindReqsFilter(sender.FindRequestsFilter{})\n\tsvc.scope.SetRules(nil)\n\n\treturn nil\n}\n\n// DeleteProject removes a project from the repository.\nfunc (svc *Service) DeleteProject(ctx context.Context, projectID ulid.ULID) error {\n\tif svc.activeProjectID.Compare(projectID) == 0 {\n\t\treturn fmt.Errorf(\"proj: project (%v) is active\", projectID.String())\n\t}\n\n\tif err := svc.repo.DeleteProject(ctx, projectID); err != nil {\n\t\treturn fmt.Errorf(\"proj: could not delete project: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// OpenProject sets a project as the currently active project.\nfunc (svc *Service) OpenProject(ctx context.Context, projectID ulid.ULID) (Project, error) {\n\tsvc.mu.Lock()\n\tdefer svc.mu.Unlock()\n\n\tproject, err := svc.repo.FindProjectByID(ctx, projectID)\n\tif err != nil {\n\t\treturn Project{}, fmt.Errorf(\"proj: failed to get project: %w\", err)\n\t}\n\n\tsvc.activeProjectID = project.ID\n\n\t// Request log settings.\n\tsvc.reqLogSvc.SetFindReqsFilter(reqlog.FindRequestsFilter{\n\t\tProjectID:   project.ID,\n\t\tOnlyInScope: project.Settings.ReqLogOnlyFindInScope,\n\t\tSearchExpr:  project.Settings.ReqLogSearchExpr,\n\t})\n\tsvc.reqLogSvc.SetBypassOutOfScopeRequests(project.Settings.ReqLogBypassOutOfScope)\n\tsvc.reqLogSvc.SetActiveProjectID(project.ID)\n\n\t// Intercept settings.\n\tsvc.interceptSvc.UpdateSettings(intercept.Settings{\n\t\tRequestsEnabled:  project.Settings.InterceptRequests,\n\t\tResponsesEnabled: project.Settings.InterceptResponses,\n\t\tRequestFilter:    project.Settings.InterceptRequestFilter,\n\t\tResponseFilter:   project.Settings.InterceptResponseFilter,\n\t})\n\n\t// Sender settings.\n\tsvc.senderSvc.SetActiveProjectID(project.ID)\n\tsvc.senderSvc.SetFindReqsFilter(sender.FindRequestsFilter{\n\t\tProjectID:   project.ID,\n\t\tOnlyInScope: project.Settings.SenderOnlyFindInScope,\n\t\tSearchExpr:  project.Settings.SenderSearchExpr,\n\t})\n\n\t// Scope settings.\n\tsvc.scope.SetRules(project.Settings.ScopeRules)\n\n\treturn project, nil\n}\n\nfunc (svc *Service) ActiveProject(ctx context.Context) (Project, error) {\n\tactiveProjectID := svc.activeProjectID\n\tif activeProjectID.Compare(ulid.ULID{}) == 0 {\n\t\treturn Project{}, ErrNoProject\n\t}\n\n\tproject, err := svc.repo.FindProjectByID(ctx, activeProjectID)\n\tif err != nil {\n\t\treturn Project{}, fmt.Errorf(\"proj: failed to get active project: %w\", err)\n\t}\n\n\tproject.isActive = true\n\n\treturn project, nil\n}\n\nfunc (svc *Service) Projects(ctx context.Context) ([]Project, error) {\n\tprojects, err := svc.repo.Projects(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"proj: could not get projects: %w\", err)\n\t}\n\n\treturn projects, nil\n}\n\nfunc (svc *Service) Scope() *scope.Scope {\n\treturn svc.scope\n}\n\nfunc (svc *Service) SetScopeRules(ctx context.Context, rules []scope.Rule) error {\n\tproject, err := svc.ActiveProject(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tproject.Settings.ScopeRules = rules\n\n\terr = svc.repo.UpsertProject(ctx, project)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"proj: failed to update project: %w\", err)\n\t}\n\n\tsvc.scope.SetRules(rules)\n\n\treturn nil\n}\n\nfunc (svc *Service) SetRequestLogFindFilter(ctx context.Context, filter reqlog.FindRequestsFilter) error {\n\tproject, err := svc.ActiveProject(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfilter.ProjectID = project.ID\n\n\tproject.Settings.ReqLogOnlyFindInScope = filter.OnlyInScope\n\tproject.Settings.ReqLogSearchExpr = filter.SearchExpr\n\n\terr = svc.repo.UpsertProject(ctx, project)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"proj: failed to update project: %w\", err)\n\t}\n\n\tsvc.reqLogSvc.SetFindReqsFilter(filter)\n\n\treturn nil\n}\n\nfunc (svc *Service) SetSenderRequestFindFilter(ctx context.Context, filter sender.FindRequestsFilter) error {\n\tproject, err := svc.ActiveProject(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfilter.ProjectID = project.ID\n\n\tproject.Settings.SenderOnlyFindInScope = filter.OnlyInScope\n\tproject.Settings.SenderSearchExpr = filter.SearchExpr\n\n\terr = svc.repo.UpsertProject(ctx, project)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"proj: failed to update project: %w\", err)\n\t}\n\n\tsvc.senderSvc.SetFindReqsFilter(filter)\n\n\treturn nil\n}\n\nfunc (svc *Service) IsProjectActive(projectID ulid.ULID) bool {\n\treturn projectID.Compare(svc.activeProjectID) == 0\n}\n\nfunc (svc *Service) UpdateInterceptSettings(ctx context.Context, settings intercept.Settings) error {\n\tproject, err := svc.ActiveProject(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tproject.Settings.InterceptRequests = settings.RequestsEnabled\n\tproject.Settings.InterceptResponses = settings.ResponsesEnabled\n\tproject.Settings.InterceptRequestFilter = settings.RequestFilter\n\tproject.Settings.InterceptResponseFilter = settings.ResponseFilter\n\n\terr = svc.repo.UpsertProject(ctx, project)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"proj: failed to update project: %w\", err)\n\t}\n\n\tsvc.interceptSvc.UpdateSettings(settings)\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/proj/repo.go",
    "content": "package proj\n\nimport (\n\t\"context\"\n\n\t\"github.com/oklog/ulid\"\n)\n\ntype Repository interface {\n\tFindProjectByID(ctx context.Context, id ulid.ULID) (Project, error)\n\tUpsertProject(ctx context.Context, project Project) error\n\tDeleteProject(ctx context.Context, id ulid.ULID) error\n\tProjects(ctx context.Context) ([]Project, error)\n\tClose() error\n}\n"
  },
  {
    "path": "pkg/proxy/cert.go",
    "content": "package proxy\n\nimport (\n\t\"bytes\"\n\t\"crypto\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/sha1\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n)\n\n// MaxSerialNumber is the upper boundary that is used to create unique serial\n// numbers for the certificate. This can be any unsigned integer up to 20\n// bytes (2^(8*20)-1).\nvar MaxSerialNumber = big.NewInt(0).SetBytes(bytes.Repeat([]byte{255}, 20))\n\n// CertConfig is a set of configuration values that are used to build TLS configs\n// capable of MITM.\ntype CertConfig struct {\n\tca     *x509.Certificate\n\tcaPriv crypto.PrivateKey\n\tpriv   *rsa.PrivateKey\n\tkeyID  []byte\n}\n\n// NewCertConfig creates a MITM config using the CA certificate and\n// private key to generate on-the-fly certificates.\nfunc NewCertConfig(ca *x509.Certificate, caPrivKey crypto.PrivateKey) (*CertConfig, error) {\n\tpriv, err := rsa.GenerateKey(rand.Reader, 2048)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpub := priv.Public()\n\n\t// Subject Key Identifier support for end entity certificate.\n\t// https://www.ietf.org/rfc/rfc3280.txt (section 4.2.1.2)\n\tpkixPubKey, err := x509.MarshalPKIXPublicKey(pub)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\th := sha1.New()\n\th.Write(pkixPubKey)\n\tkeyID := h.Sum(nil)\n\n\treturn &CertConfig{\n\t\tca:     ca,\n\t\tcaPriv: caPrivKey,\n\t\tpriv:   priv,\n\t\tkeyID:  keyID,\n\t}, nil\n}\n\n// LoadOrCreateCA loads an existing CA key pair from disk, or creates\n// a new keypair and saves to disk if certificate or key files don't exist.\nfunc LoadOrCreateCA(caKeyFile, caCertFile string) (*x509.Certificate, *rsa.PrivateKey, error) {\n\ttlsCA, err := tls.LoadX509KeyPair(caCertFile, caKeyFile)\n\tif err == nil {\n\t\tcaCert, err := x509.ParseCertificate(tlsCA.Certificate[0])\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"proxy: could not parse CA: %w\", err)\n\t\t}\n\n\t\tcaKey, ok := tlsCA.PrivateKey.(*rsa.PrivateKey)\n\t\tif !ok {\n\t\t\treturn nil, nil, errors.New(\"proxy: private key is not RSA\")\n\t\t}\n\n\t\treturn caCert, caKey, nil\n\t}\n\n\tif !os.IsNotExist(err) {\n\t\treturn nil, nil, fmt.Errorf(\"proxy: could not load CA key pair: %w\", err)\n\t}\n\n\t// Create directories for files if they don't exist yet.\n\tkeyDir, _ := filepath.Split(caKeyFile)\n\tif keyDir != \"\" {\n\t\tif _, err := os.Stat(keyDir); os.IsNotExist(err) {\n\t\t\tif err := os.MkdirAll(keyDir, 0o755); err != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"proxy: could not create directory for CA key: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\tkeyDir, _ = filepath.Split(caCertFile)\n\tif keyDir != \"\" {\n\t\tif _, err := os.Stat(\"keyDir\"); os.IsNotExist(err) {\n\t\t\tif err := os.MkdirAll(keyDir, 0o755); err != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"proxy: could not create directory for CA cert: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Create new CA keypair.\n\tcaCert, caKey, err := NewCA(\"Hetty\", \"Hetty CA\", 365*24*time.Hour)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"proxy: could not generate new CA keypair: %w\", err)\n\t}\n\n\t// Open CA certificate and key files for writing.\n\tcertOut, err := os.Create(caCertFile)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"proxy: could not open cert file for writing: %w\", err)\n\t}\n\n\tkeyOut, err := os.OpenFile(caKeyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"proxy: could not open key file for writing: %w\", err)\n\t}\n\n\t// Write PEM blocks to CA certificate and key files.\n\tif err := pem.Encode(certOut, &pem.Block{Type: \"CERTIFICATE\", Bytes: caCert.Raw}); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"proxy: could not write CA certificate to disk: %w\", err)\n\t}\n\n\tprivBytes, err := x509.MarshalPKCS8PrivateKey(caKey)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"proxy: could not convert private key to DER format: %w\", err)\n\t}\n\n\tif err := pem.Encode(keyOut, &pem.Block{Type: \"PRIVATE KEY\", Bytes: privBytes}); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"proxy: could not write CA key to disk: %w\", err)\n\t}\n\n\treturn caCert, caKey, nil\n}\n\n// NewCA creates a new CA certificate and associated private key.\nfunc NewCA(name, organization string, validity time.Duration) (*x509.Certificate, *rsa.PrivateKey, error) {\n\tpriv, err := rsa.GenerateKey(rand.Reader, 2048)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tpub := priv.Public()\n\n\t// Subject Key Identifier support for end entity certificate.\n\t// https://www.ietf.org/rfc/rfc3280.txt (section 4.2.1.2)\n\tpkixpub, err := x509.MarshalPKIXPublicKey(pub)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\th := sha1.New()\n\th.Write(pkixpub)\n\tkeyID := h.Sum(nil)\n\n\t// TODO: keep a map of used serial numbers to avoid potentially reusing a\n\t// serial multiple times.\n\tserial, err := rand.Int(rand.Reader, MaxSerialNumber)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\ttmpl := &x509.Certificate{\n\t\tSerialNumber: serial,\n\t\tSubject: pkix.Name{\n\t\t\tCommonName:   name,\n\t\t\tOrganization: []string{organization},\n\t\t},\n\t\tSubjectKeyId:          keyID,\n\t\tKeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,\n\t\tExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},\n\t\tBasicConstraintsValid: true,\n\t\tNotBefore:             time.Now(),\n\t\tNotAfter:              time.Now().Add(validity),\n\t\tDNSNames:              []string{name},\n\t\tIsCA:                  true,\n\t}\n\n\traw, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, pub, priv)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Parse certificate bytes so that we have a leaf certificate.\n\tx509c, err := x509.ParseCertificate(raw)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn x509c, priv, nil\n}\n\n// TLSConfig returns a *tls.Config that will generate certificates on-the-fly using\n// the SNI extension in the TLS ClientHello.\nfunc (c *CertConfig) TLSConfig() *tls.Config {\n\treturn &tls.Config{\n\t\tGetCertificate: func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {\n\t\t\tif clientHello.ServerName == \"\" {\n\t\t\t\treturn nil, errors.New(\"missing server name (SNI)\")\n\t\t\t}\n\n\t\t\treturn c.cert(clientHello.ServerName)\n\t\t},\n\t\tMinVersion: tls.VersionTLS12,\n\t\tNextProtos: []string{\"http/1.1\"},\n\t}\n}\n\nfunc (c *CertConfig) cert(hostname string) (*tls.Certificate, error) {\n\t// Remove the port if it exists.\n\thost, _, err := net.SplitHostPort(hostname)\n\tif err == nil {\n\t\thostname = host\n\t}\n\n\tserial, err := rand.Int(rand.Reader, MaxSerialNumber)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttmpl := &x509.Certificate{\n\t\tSerialNumber: serial,\n\t\tSubject: pkix.Name{\n\t\t\tCommonName:   hostname,\n\t\t\tOrganization: []string{\"Hetty\"},\n\t\t},\n\t\tSubjectKeyId:          c.keyID,\n\t\tKeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,\n\t\tExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},\n\t\tBasicConstraintsValid: true,\n\t\tNotBefore:             time.Now().Add(-24 * time.Hour),\n\t\tNotAfter:              time.Now().Add(24 * time.Hour),\n\t}\n\n\tif ip := net.ParseIP(hostname); ip != nil {\n\t\ttmpl.IPAddresses = []net.IP{ip}\n\t} else {\n\t\ttmpl.DNSNames = []string{hostname}\n\t}\n\n\traw, err := x509.CreateCertificate(rand.Reader, tmpl, c.ca, c.priv.Public(), c.caPriv)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Parse certificate bytes so that we have a leaf certificate.\n\tx509c, err := x509.ParseCertificate(raw)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &tls.Certificate{\n\t\tCertificate: [][]byte{raw, c.ca.Raw},\n\t\tPrivateKey:  c.priv,\n\t\tLeaf:        x509c,\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/proxy/gzip.go",
    "content": "package proxy\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n)\n\nfunc gunzipResponseBody(res *http.Response) error {\n\tif res.Header.Get(\"Content-Encoding\") != \"gzip\" {\n\t\treturn nil\n\t}\n\n\tgzipReader, err := gzip.NewReader(res.Body)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"proxy: could not create gzip reader: %w\", err)\n\t}\n\tdefer gzipReader.Close()\n\n\tbuf := &bytes.Buffer{}\n\n\t//nolint:gosec\n\tif _, err := io.Copy(buf, gzipReader); err != nil {\n\t\treturn fmt.Errorf(\"proxy: could not read gzipped response body: %w\", err)\n\t}\n\n\tres.Body = io.NopCloser(buf)\n\tres.Header.Del(\"Content-Encoding\")\n\tres.Header.Set(\"Content-Length\", fmt.Sprint(buf.Len()))\n\tres.ContentLength = int64(buf.Len())\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/proxy/intercept/filter.go",
    "content": "package intercept\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n)\n\n//nolint:unparam\nvar reqFilterKeyFns = map[string]func(req *http.Request) (string, error){\n\t\"proto\": func(req *http.Request) (string, error) { return req.Proto, nil },\n\t\"url\": func(req *http.Request) (string, error) {\n\t\tif req.URL == nil {\n\t\t\treturn \"\", nil\n\t\t}\n\t\treturn req.URL.String(), nil\n\t},\n\t\"method\": func(req *http.Request) (string, error) { return req.Method, nil },\n\t\"body\": func(req *http.Request) (string, error) {\n\t\tif req.Body == nil {\n\t\t\treturn \"\", nil\n\t\t}\n\n\t\tbody, err := io.ReadAll(req.Body)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\treq.Body = ioutil.NopCloser(bytes.NewBuffer(body))\n\t\treturn string(body), nil\n\t},\n}\n\n//nolint:unparam\nvar resFilterKeyFns = map[string]func(res *http.Response) (string, error){\n\t\"proto\":      func(res *http.Response) (string, error) { return res.Proto, nil },\n\t\"statusCode\": func(res *http.Response) (string, error) { return strconv.Itoa(res.StatusCode), nil },\n\t\"statusReason\": func(res *http.Response) (string, error) {\n\t\tstatusReasonSubs := strings.SplitN(res.Status, \" \", 2)\n\n\t\tif len(statusReasonSubs) != 2 {\n\t\t\treturn \"\", fmt.Errorf(\"invalid response status %q\", res.Status)\n\t\t}\n\t\treturn statusReasonSubs[1], nil\n\t},\n\t\"body\": func(res *http.Response) (string, error) {\n\t\tif res.Body == nil {\n\t\t\treturn \"\", nil\n\t\t}\n\n\t\tbody, err := io.ReadAll(res.Body)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tres.Body = ioutil.NopCloser(bytes.NewBuffer(body))\n\n\t\treturn string(body), nil\n\t},\n}\n\n// MatchRequestFilter returns true if an HTTP request matches the request filter expression.\nfunc MatchRequestFilter(req *http.Request, expr filter.Expression) (bool, error) {\n\tswitch e := expr.(type) {\n\tcase filter.PrefixExpression:\n\t\treturn matchReqPrefixExpr(req, e)\n\tcase filter.InfixExpression:\n\t\treturn matchReqInfixExpr(req, e)\n\tcase filter.StringLiteral:\n\t\treturn matchReqStringLiteral(req, e)\n\tdefault:\n\t\treturn false, fmt.Errorf(\"expression type (%T) not supported\", expr)\n\t}\n}\n\nfunc matchReqPrefixExpr(req *http.Request, expr filter.PrefixExpression) (bool, error) {\n\tswitch expr.Operator {\n\tcase filter.TokOpNot:\n\t\tmatch, err := MatchRequestFilter(req, expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn !match, nil\n\tdefault:\n\t\treturn false, errors.New(\"operator is not supported\")\n\t}\n}\n\nfunc matchReqInfixExpr(req *http.Request, expr filter.InfixExpression) (bool, error) {\n\tswitch expr.Operator {\n\tcase filter.TokOpAnd:\n\t\tleft, err := MatchRequestFilter(req, expr.Left)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tright, err := MatchRequestFilter(req, expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn left && right, nil\n\tcase filter.TokOpOr:\n\t\tleft, err := MatchRequestFilter(req, expr.Left)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tright, err := MatchRequestFilter(req, expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn left || right, nil\n\t}\n\n\tleft, ok := expr.Left.(filter.StringLiteral)\n\tif !ok {\n\t\treturn false, errors.New(\"left operand must be a string literal\")\n\t}\n\n\tleftVal, err := getMappedStringLiteralFromReq(req, left.Value)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to get string literal from request for left operand: %w\", err)\n\t}\n\n\tif leftVal == \"headers\" {\n\t\tmatch, err := filter.MatchHTTPHeaders(expr.Operator, expr.Right, req.Header)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to match request HTTP headers: %w\", err)\n\t\t}\n\n\t\treturn match, nil\n\t}\n\n\tif expr.Operator == filter.TokOpRe || expr.Operator == filter.TokOpNotRe {\n\t\tright, ok := expr.Right.(filter.RegexpLiteral)\n\t\tif !ok {\n\t\t\treturn false, errors.New(\"right operand must be a regular expression\")\n\t\t}\n\n\t\tswitch expr.Operator {\n\t\tcase filter.TokOpRe:\n\t\t\treturn right.MatchString(leftVal), nil\n\t\tcase filter.TokOpNotRe:\n\t\t\treturn !right.MatchString(leftVal), nil\n\t\t}\n\t}\n\n\tright, ok := expr.Right.(filter.StringLiteral)\n\tif !ok {\n\t\treturn false, errors.New(\"right operand must be a string literal\")\n\t}\n\n\trightVal, err := getMappedStringLiteralFromReq(req, right.Value)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to get string literal from request for right operand: %w\", err)\n\t}\n\n\tswitch expr.Operator {\n\tcase filter.TokOpEq:\n\t\treturn leftVal == rightVal, nil\n\tcase filter.TokOpNotEq:\n\t\treturn leftVal != rightVal, nil\n\tcase filter.TokOpGt:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal > rightVal, nil\n\tcase filter.TokOpLt:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal < rightVal, nil\n\tcase filter.TokOpGtEq:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal >= rightVal, nil\n\tcase filter.TokOpLtEq:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal <= rightVal, nil\n\tdefault:\n\t\treturn false, errors.New(\"unsupported operator\")\n\t}\n}\n\nfunc getMappedStringLiteralFromReq(req *http.Request, s string) (string, error) {\n\tfn, ok := reqFilterKeyFns[s]\n\tif ok {\n\t\treturn fn(req)\n\t}\n\n\treturn s, nil\n}\n\nfunc matchReqStringLiteral(req *http.Request, strLiteral filter.StringLiteral) (bool, error) {\n\tfor key, values := range req.Header {\n\t\tfor _, value := range values {\n\t\t\tif strings.Contains(\n\t\t\t\tstrings.ToLower(fmt.Sprintf(\"%v: %v\", key, value)),\n\t\t\t\tstrings.ToLower(strLiteral.Value),\n\t\t\t) {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, fn := range reqFilterKeyFns {\n\t\tvalue, err := fn(req)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tif strings.Contains(strings.ToLower(value), strings.ToLower(strLiteral.Value)) {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\n\treturn false, nil\n}\n\nfunc MatchRequestScope(req *http.Request, s *scope.Scope) (bool, error) {\n\tfor _, rule := range s.Rules() {\n\t\tif rule.URL != nil && req.URL != nil {\n\t\t\tif matches := rule.URL.MatchString(req.URL.String()); matches {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t}\n\n\t\tfor key, values := range req.Header {\n\t\t\tvar keyMatches, valueMatches bool\n\n\t\t\tif rule.Header.Key != nil {\n\t\t\t\tif matches := rule.Header.Key.MatchString(key); matches {\n\t\t\t\t\tkeyMatches = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif rule.Header.Value != nil {\n\t\t\t\tfor _, value := range values {\n\t\t\t\t\tif matches := rule.Header.Value.MatchString(value); matches {\n\t\t\t\t\t\tvalueMatches = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// When only key or value is set, match on whatever is set.\n\t\t\t// When both are set, both must match.\n\t\t\tswitch {\n\t\t\tcase rule.Header.Key != nil && rule.Header.Value == nil && keyMatches:\n\t\t\t\treturn true, nil\n\t\t\tcase rule.Header.Key == nil && rule.Header.Value != nil && valueMatches:\n\t\t\t\treturn true, nil\n\t\t\tcase rule.Header.Key != nil && rule.Header.Value != nil && keyMatches && valueMatches:\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t}\n\n\t\tif rule.Body != nil {\n\t\t\tbody, err := io.ReadAll(req.Body)\n\t\t\tif err != nil {\n\t\t\t\treturn false, fmt.Errorf(\"failed to read request body: %w\", err)\n\t\t\t}\n\n\t\t\treq.Body = ioutil.NopCloser(bytes.NewBuffer(body))\n\n\t\t\tif matches := rule.Body.Match(body); matches {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false, nil\n}\n\n// MatchResponseFilter returns true if an HTTP response matches the response filter expression.\nfunc MatchResponseFilter(res *http.Response, expr filter.Expression) (bool, error) {\n\tswitch e := expr.(type) {\n\tcase filter.PrefixExpression:\n\t\treturn matchResPrefixExpr(res, e)\n\tcase filter.InfixExpression:\n\t\treturn matchResInfixExpr(res, e)\n\tcase filter.StringLiteral:\n\t\treturn matchResStringLiteral(res, e)\n\tdefault:\n\t\treturn false, fmt.Errorf(\"expression type (%T) not supported\", expr)\n\t}\n}\n\nfunc matchResPrefixExpr(res *http.Response, expr filter.PrefixExpression) (bool, error) {\n\tswitch expr.Operator {\n\tcase filter.TokOpNot:\n\t\tmatch, err := MatchResponseFilter(res, expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn !match, nil\n\tdefault:\n\t\treturn false, errors.New(\"operator is not supported\")\n\t}\n}\n\nfunc matchResInfixExpr(res *http.Response, expr filter.InfixExpression) (bool, error) {\n\tswitch expr.Operator {\n\tcase filter.TokOpAnd:\n\t\tleft, err := MatchResponseFilter(res, expr.Left)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tright, err := MatchResponseFilter(res, expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn left && right, nil\n\tcase filter.TokOpOr:\n\t\tleft, err := MatchResponseFilter(res, expr.Left)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tright, err := MatchResponseFilter(res, expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn left || right, nil\n\t}\n\n\tleft, ok := expr.Left.(filter.StringLiteral)\n\tif !ok {\n\t\treturn false, errors.New(\"left operand must be a string literal\")\n\t}\n\n\tleftVal, err := getMappedStringLiteralFromRes(res, left.Value)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to get string literal from response for left operand: %w\", err)\n\t}\n\n\tif leftVal == \"headers\" {\n\t\tmatch, err := filter.MatchHTTPHeaders(expr.Operator, expr.Right, res.Header)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to match request HTTP headers: %w\", err)\n\t\t}\n\n\t\treturn match, nil\n\t}\n\n\tif expr.Operator == filter.TokOpRe || expr.Operator == filter.TokOpNotRe {\n\t\tright, ok := expr.Right.(filter.RegexpLiteral)\n\t\tif !ok {\n\t\t\treturn false, errors.New(\"right operand must be a regular expression\")\n\t\t}\n\n\t\tswitch expr.Operator {\n\t\tcase filter.TokOpRe:\n\t\t\treturn right.MatchString(leftVal), nil\n\t\tcase filter.TokOpNotRe:\n\t\t\treturn !right.MatchString(leftVal), nil\n\t\t}\n\t}\n\n\tright, ok := expr.Right.(filter.StringLiteral)\n\tif !ok {\n\t\treturn false, errors.New(\"right operand must be a string literal\")\n\t}\n\n\trightVal, err := getMappedStringLiteralFromRes(res, right.Value)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to get string literal from response for right operand: %w\", err)\n\t}\n\n\tswitch expr.Operator {\n\tcase filter.TokOpEq:\n\t\treturn leftVal == rightVal, nil\n\tcase filter.TokOpNotEq:\n\t\treturn leftVal != rightVal, nil\n\tcase filter.TokOpGt:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal > rightVal, nil\n\tcase filter.TokOpLt:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal < rightVal, nil\n\tcase filter.TokOpGtEq:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal >= rightVal, nil\n\tcase filter.TokOpLtEq:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal <= rightVal, nil\n\tdefault:\n\t\treturn false, errors.New(\"unsupported operator\")\n\t}\n}\n\nfunc getMappedStringLiteralFromRes(res *http.Response, s string) (string, error) {\n\tfn, ok := resFilterKeyFns[s]\n\tif ok {\n\t\treturn fn(res)\n\t}\n\n\treturn s, nil\n}\n\nfunc matchResStringLiteral(res *http.Response, strLiteral filter.StringLiteral) (bool, error) {\n\tfor key, values := range res.Header {\n\t\tfor _, value := range values {\n\t\t\tif strings.Contains(\n\t\t\t\tstrings.ToLower(fmt.Sprintf(\"%v: %v\", key, value)),\n\t\t\t\tstrings.ToLower(strLiteral.Value),\n\t\t\t) {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, fn := range resFilterKeyFns {\n\t\tvalue, err := fn(res)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tif strings.Contains(strings.ToLower(value), strings.ToLower(strLiteral.Value)) {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\n\treturn false, nil\n}\n"
  },
  {
    "path": "pkg/proxy/intercept/intercept.go",
    "content": "package intercept\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sort\"\n\t\"sync\"\n\n\t\"github.com/oklog/ulid\"\n\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n\t\"github.com/dstotijn/hetty/pkg/log\"\n\t\"github.com/dstotijn/hetty/pkg/proxy\"\n)\n\nvar (\n\tErrRequestAborted   = errors.New(\"intercept: request was aborted\")\n\tErrRequestNotFound  = errors.New(\"intercept: request not found\")\n\tErrRequestDone      = errors.New(\"intercept: request is done\")\n\tErrResponseNotFound = errors.New(\"intercept: response not found\")\n)\n\ntype contextKey int\n\nconst interceptResponseKey contextKey = 0\n\n// Request represents a server received HTTP request, alongside a channel for sending a modified version of it to the\n// routine that's awaiting it. Also contains a channel for receiving a cancellation signal.\ntype Request struct {\n\treq  *http.Request\n\tch   chan<- *http.Request\n\tdone <-chan struct{}\n}\n\n// Response represents an HTTP response from a proxied request, alongside a channel for sending a modified version of it\n// to the routine that's awaiting it. Also contains a channel for receiving a cancellation signal.\ntype Response struct {\n\tres  *http.Response\n\tch   chan<- *http.Response\n\tdone <-chan struct{}\n}\n\ntype Item struct {\n\tRequest  *http.Request\n\tResponse *http.Response\n}\n\ntype Service struct {\n\treqMu     *sync.RWMutex\n\tresMu     *sync.RWMutex\n\trequests  map[ulid.ULID]Request\n\tresponses map[ulid.ULID]Response\n\tlogger    log.Logger\n\n\trequestsEnabled  bool\n\tresponsesEnabled bool\n\treqFilter        filter.Expression\n\tresFilter        filter.Expression\n}\n\ntype Config struct {\n\tLogger           log.Logger\n\tRequestsEnabled  bool\n\tResponsesEnabled bool\n\tRequestFilter    filter.Expression\n\tResponseFilter   filter.Expression\n}\n\n// RequestIDs implements sort.Interface.\ntype RequestIDs []ulid.ULID\n\nfunc NewService(cfg Config) *Service {\n\ts := &Service{\n\t\treqMu:            &sync.RWMutex{},\n\t\tresMu:            &sync.RWMutex{},\n\t\trequests:         make(map[ulid.ULID]Request),\n\t\tresponses:        make(map[ulid.ULID]Response),\n\t\tlogger:           cfg.Logger,\n\t\trequestsEnabled:  cfg.RequestsEnabled,\n\t\tresponsesEnabled: cfg.ResponsesEnabled,\n\t\treqFilter:        cfg.RequestFilter,\n\t\tresFilter:        cfg.ResponseFilter,\n\t}\n\n\tif s.logger == nil {\n\t\ts.logger = log.NewNopLogger()\n\t}\n\n\treturn s\n}\n\n// RequestModifier is a proxy.RequestModifyMiddleware for intercepting HTTP requests.\nfunc (svc *Service) RequestModifier(next proxy.RequestModifyFunc) proxy.RequestModifyFunc {\n\treturn func(req *http.Request) {\n\t\t// This is a blocking operation, that gets unblocked when either a modified request is returned or an error\n\t\t// (typically `context.Canceled`).\n\t\tmodifiedReq, err := svc.InterceptRequest(req.Context(), req)\n\n\t\tswitch {\n\t\tcase errors.Is(err, ErrRequestAborted):\n\t\t\tsvc.logger.Debugw(\"Stopping intercept, request was aborted.\")\n\t\t\t// Prevent further processing by replacing req.Context with a cancelled context value.\n\t\t\t// This will cause the http.Roundtripper in the `proxy` package to\n\t\t\t// handle this request as an error.\n\t\t\tctx, cancel := context.WithCancel(context.Background())\n\t\t\tcancel()\n\n\t\t\t*req = *req.WithContext(ctx)\n\t\tcase errors.Is(err, context.Canceled):\n\t\t\tsvc.logger.Debugw(\"Stopping intercept, context was cancelled.\")\n\t\tcase err != nil:\n\t\t\tsvc.logger.Errorw(\"Failed to intercept request.\",\n\t\t\t\t\"error\", err)\n\t\tdefault:\n\t\t\t*req = *modifiedReq\n\t\t\tnext(req)\n\t\t}\n\t}\n}\n\n// InterceptRequest adds an HTTP request to an array of pending intercepted requests, alongside channels used for\n// sending a cancellation signal and receiving a modified request. It's safe for concurrent use.\nfunc (svc *Service) InterceptRequest(ctx context.Context, req *http.Request) (*http.Request, error) {\n\treqID, ok := proxy.RequestIDFromContext(ctx)\n\tif !ok {\n\t\tsvc.logger.Errorw(\"Failed to intercept: context doesn't have an ID.\")\n\t\treturn req, nil\n\t}\n\n\tif !svc.requestsEnabled {\n\t\t// If request intercept is disabled, return the incoming request as-is.\n\t\tsvc.logger.Debugw(\"Bypassed request interception: feature disabled.\")\n\t\treturn req, nil\n\t}\n\n\tif svc.reqFilter != nil {\n\t\tmatch, err := MatchRequestFilter(req, svc.reqFilter)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"intercept: failed to match request rules for request (id: %v): %w\",\n\t\t\t\treqID.String(), err,\n\t\t\t)\n\t\t}\n\n\t\tif !match {\n\t\t\tsvc.logger.Debugw(\"Bypassed request interception: request rules don't match.\")\n\t\t\treturn req, nil\n\t\t}\n\t}\n\n\tch := make(chan *http.Request)\n\tdone := make(chan struct{})\n\n\tsvc.reqMu.Lock()\n\tsvc.requests[reqID] = Request{\n\t\treq:  req,\n\t\tch:   ch,\n\t\tdone: done,\n\t}\n\tsvc.reqMu.Unlock()\n\n\t// Whatever happens next (modified request returned, or a context cancelled error), any blocked channel senders\n\t// should be unblocked, and the request should be removed from the requests queue.\n\tdefer func() {\n\t\tclose(done)\n\t\tsvc.reqMu.Lock()\n\t\tdefer svc.reqMu.Unlock()\n\t\tdelete(svc.requests, reqID)\n\t}()\n\n\tselect {\n\tcase modReq := <-ch:\n\t\tif modReq == nil {\n\t\t\treturn nil, ErrRequestAborted\n\t\t}\n\n\t\treturn modReq, nil\n\tcase <-ctx.Done():\n\t\treturn nil, ctx.Err()\n\t}\n}\n\n// ModifyRequest sends a modified HTTP request to the related channel, or returns ErrRequestDone when the request was\n// cancelled. It's safe for concurrent use.\nfunc (svc *Service) ModifyRequest(reqID ulid.ULID, modReq *http.Request, modifyResponse *bool) error {\n\tsvc.reqMu.RLock()\n\treq, ok := svc.requests[reqID]\n\tsvc.reqMu.RUnlock()\n\n\tif !ok {\n\t\treturn ErrRequestNotFound\n\t}\n\n\t*modReq = *modReq.WithContext(req.req.Context())\n\tif modifyResponse != nil {\n\t\t*modReq = *modReq.WithContext(WithInterceptResponse(modReq.Context(), *modifyResponse))\n\t}\n\n\tselect {\n\tcase <-req.done:\n\t\treturn ErrRequestDone\n\tcase req.ch <- modReq:\n\t\treturn nil\n\t}\n}\n\n// CancelRequest ensures an intercepted request is dropped.\nfunc (svc *Service) CancelRequest(reqID ulid.ULID) error {\n\treturn svc.ModifyRequest(reqID, nil, nil)\n}\n\nfunc (svc *Service) ClearRequests() {\n\tsvc.reqMu.Lock()\n\tdefer svc.reqMu.Unlock()\n\n\tfor _, req := range svc.requests {\n\t\tselect {\n\t\tcase <-req.done:\n\t\tcase req.ch <- nil:\n\t\t}\n\t}\n}\n\nfunc (svc *Service) ClearResponses() {\n\tsvc.resMu.Lock()\n\tdefer svc.resMu.Unlock()\n\n\tfor _, res := range svc.responses {\n\t\tselect {\n\t\tcase <-res.done:\n\t\tcase res.ch <- nil:\n\t\t}\n\t}\n}\n\n// Items returns a list of pending items (requests and responses). It's safe for concurrent use.\nfunc (svc *Service) Items() []Item {\n\tsvc.reqMu.RLock()\n\tdefer svc.reqMu.RUnlock()\n\n\tsvc.resMu.RLock()\n\tdefer svc.resMu.RUnlock()\n\n\treqIDs := make([]ulid.ULID, 0, len(svc.requests)+len(svc.responses))\n\n\tfor id := range svc.requests {\n\t\treqIDs = append(reqIDs, id)\n\t}\n\n\tfor id := range svc.responses {\n\t\treqIDs = append(reqIDs, id)\n\t}\n\n\tsort.Sort(RequestIDs(reqIDs))\n\n\titems := make([]Item, len(reqIDs))\n\n\tfor i, id := range reqIDs {\n\t\titem := Item{}\n\n\t\tif req, ok := svc.requests[id]; ok {\n\t\t\titem.Request = req.req\n\t\t}\n\n\t\tif res, ok := svc.responses[id]; ok {\n\t\t\titem.Response = res.res\n\t\t}\n\n\t\titems[i] = item\n\t}\n\n\treturn items\n}\n\nfunc (svc *Service) UpdateSettings(settings Settings) {\n\t// When updating from requests `enabled` -> `disabled`, clear any pending reqs.\n\tif svc.requestsEnabled && !settings.RequestsEnabled {\n\t\tsvc.ClearRequests()\n\t}\n\n\t// When updating from responses `enabled` -> `disabled`, clear any pending responses.\n\tif svc.responsesEnabled && !settings.ResponsesEnabled {\n\t\tsvc.ClearResponses()\n\t}\n\n\tsvc.requestsEnabled = settings.RequestsEnabled\n\tsvc.responsesEnabled = settings.ResponsesEnabled\n\tsvc.reqFilter = settings.RequestFilter\n\tsvc.resFilter = settings.ResponseFilter\n}\n\n// ItemByID returns an intercepted item (request and possible response) by ID. It's safe for concurrent use.\nfunc (svc *Service) ItemByID(id ulid.ULID) (Item, error) {\n\tsvc.reqMu.RLock()\n\tdefer svc.reqMu.RUnlock()\n\n\tsvc.resMu.RLock()\n\tdefer svc.resMu.RUnlock()\n\n\titem := Item{}\n\tfound := false\n\n\tif req, ok := svc.requests[id]; ok {\n\t\titem.Request = req.req\n\t\tfound = true\n\t}\n\n\tif res, ok := svc.responses[id]; ok {\n\t\titem.Response = res.res\n\t\tfound = true\n\t}\n\n\tif !found {\n\t\treturn Item{}, ErrRequestNotFound\n\t}\n\n\treturn item, nil\n}\n\nfunc (ids RequestIDs) Len() int {\n\treturn len(ids)\n}\n\nfunc (ids RequestIDs) Less(i, j int) bool {\n\treturn ids[i].Compare(ids[j]) == -1\n}\n\nfunc (ids RequestIDs) Swap(i, j int) {\n\tids[i], ids[j] = ids[j], ids[i]\n}\n\nfunc WithInterceptResponse(ctx context.Context, value bool) context.Context {\n\treturn context.WithValue(ctx, interceptResponseKey, value)\n}\n\nfunc ShouldInterceptResponseFromContext(ctx context.Context) (bool, bool) {\n\tshouldIntercept, ok := ctx.Value(interceptResponseKey).(bool)\n\treturn shouldIntercept, ok\n}\n\n// ResponseModifier is a proxy.ResponseModifyMiddleware for intercepting HTTP responses.\nfunc (svc *Service) ResponseModifier(next proxy.ResponseModifyFunc) proxy.ResponseModifyFunc {\n\treturn func(res *http.Response) error {\n\t\t// This is a blocking operation, that gets unblocked when either a modified response is returned or an error.\n\t\t//nolint:bodyclose\n\t\tmodifiedRes, err := svc.InterceptResponse(res.Request.Context(), res)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to intercept response: %w\", err)\n\t\t}\n\n\t\t*res = *modifiedRes\n\n\t\treturn next(res)\n\t}\n}\n\n// InterceptResponse adds an HTTP response to an array of pending intercepted responses, alongside channels used for\n// sending a cancellation signal and receiving a modified response. It's safe for concurrent use.\nfunc (svc *Service) InterceptResponse(ctx context.Context, res *http.Response) (*http.Response, error) {\n\treqID, ok := proxy.RequestIDFromContext(ctx)\n\tif !ok {\n\t\tsvc.logger.Errorw(\"Failed to intercept: context doesn't have an ID.\")\n\t\treturn res, nil\n\t}\n\n\tshouldIntercept, ok := ShouldInterceptResponseFromContext(ctx)\n\tif ok && !shouldIntercept {\n\t\t// If the related request explicitly disabled response intercept, return the response as-is.\n\t\tsvc.logger.Debugw(\"Bypassed response interception: related request explicitly disabled response intercept.\")\n\t\treturn res, nil\n\t}\n\n\t// If global response intercept is disabled and interception is *not* explicitly enabled for this response: bypass.\n\tif !svc.responsesEnabled && !(ok && shouldIntercept) {\n\t\tsvc.logger.Debugw(\"Bypassed response interception: feature disabled.\")\n\t\treturn res, nil\n\t}\n\n\tif svc.resFilter != nil {\n\t\tmatch, err := MatchResponseFilter(res, svc.resFilter)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"intercept: failed to match response rules for response (id: %v): %w\",\n\t\t\t\treqID.String(), err,\n\t\t\t)\n\t\t}\n\n\t\tif !match {\n\t\t\tsvc.logger.Debugw(\"Bypassed response interception: response rules don't match.\")\n\t\t\treturn res, nil\n\t\t}\n\t}\n\n\tch := make(chan *http.Response)\n\tdone := make(chan struct{})\n\n\tsvc.resMu.Lock()\n\tsvc.responses[reqID] = Response{\n\t\tres:  res,\n\t\tch:   ch,\n\t\tdone: done,\n\t}\n\tsvc.resMu.Unlock()\n\n\t// Whatever happens next (modified response returned, or a context cancelled error), any blocked channel senders\n\t// should be unblocked, and the response should be removed from the responses queue.\n\tdefer func() {\n\t\tclose(done)\n\t\tsvc.resMu.Lock()\n\t\tdefer svc.resMu.Unlock()\n\t\tdelete(svc.responses, reqID)\n\t}()\n\n\tselect {\n\tcase modRes := <-ch:\n\t\tif modRes == nil {\n\t\t\treturn nil, ErrRequestAborted\n\t\t}\n\n\t\treturn modRes, nil\n\tcase <-ctx.Done():\n\t\treturn nil, ctx.Err()\n\t}\n}\n\n// ModifyResponse sends a modified HTTP response to the related channel, or returns ErrRequestDone when the related\n// request was cancelled. It's safe for concurrent use.\nfunc (svc *Service) ModifyResponse(reqID ulid.ULID, modRes *http.Response) error {\n\tsvc.resMu.RLock()\n\tres, ok := svc.responses[reqID]\n\tsvc.resMu.RUnlock()\n\n\tif !ok {\n\t\treturn ErrRequestNotFound\n\t}\n\n\tif modRes != nil {\n\t\tmodRes.Request = res.res.Request\n\t}\n\n\tselect {\n\tcase <-res.done:\n\t\treturn ErrRequestDone\n\tcase res.ch <- modRes:\n\t\treturn nil\n\t}\n}\n\n// CancelResponse ensures an intercepted response is dropped.\nfunc (svc *Service) CancelResponse(reqID ulid.ULID) error {\n\treturn svc.ModifyResponse(reqID, nil)\n}\n"
  },
  {
    "path": "pkg/proxy/intercept/intercept_test.go",
    "content": "package intercept_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/oklog/ulid\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/dstotijn/hetty/pkg/proxy\"\n\t\"github.com/dstotijn/hetty/pkg/proxy/intercept\"\n)\n\n//nolint:gosec\nvar ulidEntropy = rand.New(rand.NewSource(time.Now().UnixNano()))\n\nfunc TestRequestModifier(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"modify request that's not found\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tlogger, _ := zap.NewDevelopment()\n\t\tsvc := intercept.NewService(intercept.Config{\n\t\t\tLogger:           logger.Sugar(),\n\t\t\tRequestsEnabled:  true,\n\t\t\tResponsesEnabled: false,\n\t\t})\n\n\t\treqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\n\t\terr := svc.ModifyRequest(reqID, nil, nil)\n\t\tif !errors.Is(err, intercept.ErrRequestNotFound) {\n\t\t\tt.Fatalf(\"expected `intercept.ErrRequestNotFound`, got: %v\", err)\n\t\t}\n\t})\n\n\tt.Run(\"modify request that's done\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tlogger, _ := zap.NewDevelopment()\n\t\tsvc := intercept.NewService(intercept.Config{\n\t\t\tLogger:           logger.Sugar(),\n\t\t\tRequestsEnabled:  true,\n\t\t\tResponsesEnabled: false,\n\t\t})\n\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tdefer cancel()\n\n\t\treq := httptest.NewRequest(\"GET\", \"https://example.com/foo\", nil)\n\t\treqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\t\t*req = *req.WithContext(ctx)\n\t\t*req = *req.WithContext(proxy.WithRequestID(req.Context(), reqID))\n\n\t\tnext := func(req *http.Request) {}\n\t\tgo svc.RequestModifier(next)(req)\n\n\t\t// Wait shortly, to allow the req modifier goroutine to add `req` to the\n\t\t// array of intercepted reqs.\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\tcancel()\n\n\t\tmodReq := req.Clone(req.Context())\n\t\tmodReq.Header.Set(\"X-Foo\", \"bar\")\n\n\t\terr := svc.ModifyRequest(reqID, modReq, nil)\n\t\tif !errors.Is(err, intercept.ErrRequestDone) {\n\t\t\tt.Fatalf(\"expected `intercept.ErrRequestDone`, got: %v\", err)\n\t\t}\n\t})\n\n\tt.Run(\"modify intercepted request\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\treq := httptest.NewRequest(\"GET\", \"https://example.com/foo\", nil)\n\t\treq.Header.Set(\"X-Foo\", \"foo\")\n\n\t\treqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\t\t*req = *req.WithContext(proxy.WithRequestID(req.Context(), reqID))\n\n\t\tmodReq := req.Clone(context.Background())\n\t\tmodReq.Header.Set(\"X-Foo\", \"bar\")\n\n\t\tlogger, _ := zap.NewDevelopment()\n\t\tsvc := intercept.NewService(intercept.Config{\n\t\t\tLogger:           logger.Sugar(),\n\t\t\tRequestsEnabled:  true,\n\t\t\tResponsesEnabled: false,\n\t\t})\n\n\t\tvar got *http.Request\n\n\t\tnext := func(req *http.Request) {\n\t\t\tgot = req.Clone(context.Background())\n\t\t}\n\n\t\tvar wg sync.WaitGroup\n\t\twg.Add(1)\n\n\t\tgo func() {\n\t\t\tsvc.RequestModifier(next)(req)\n\t\t\twg.Done()\n\t\t}()\n\n\t\t// Wait shortly, to allow the req modifier goroutine to add `req` to the\n\t\t// array of intercepted reqs.\n\t\ttime.Sleep(10 * time.Millisecond)\n\n\t\terr := svc.ModifyRequest(reqID, modReq, nil)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %v\", err)\n\t\t}\n\n\t\twg.Wait()\n\n\t\tif got == nil {\n\t\t\tt.Fatal(\"expected `got` not to be nil\")\n\t\t}\n\n\t\tif exp := \"bar\"; exp != got.Header.Get(\"X-Foo\") {\n\t\t\tt.Fatalf(\"incorrect modified request header value (expected: %v, got: %v)\", exp, got.Header.Get(\"X-Foo\"))\n\t\t}\n\t})\n}\n\nfunc TestResponseModifier(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"modify response that's not found\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tlogger, _ := zap.NewDevelopment()\n\t\tsvc := intercept.NewService(intercept.Config{\n\t\t\tLogger:           logger.Sugar(),\n\t\t\tRequestsEnabled:  false,\n\t\t\tResponsesEnabled: true,\n\t\t})\n\n\t\treqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\n\t\terr := svc.ModifyResponse(reqID, nil)\n\t\tif !errors.Is(err, intercept.ErrRequestNotFound) {\n\t\t\tt.Fatalf(\"expected `intercept.ErrRequestNotFound`, got: %v\", err)\n\t\t}\n\t})\n\n\tt.Run(\"modify response of request that's done\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tlogger, _ := zap.NewDevelopment()\n\t\tsvc := intercept.NewService(intercept.Config{\n\t\t\tLogger:           logger.Sugar(),\n\t\t\tRequestsEnabled:  false,\n\t\t\tResponsesEnabled: true,\n\t\t})\n\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tdefer cancel()\n\n\t\treq := httptest.NewRequest(\"GET\", \"https://example.com/foo\", nil)\n\t\treqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\t\t*req = *req.WithContext(ctx)\n\t\t*req = *req.WithContext(proxy.WithRequestID(req.Context(), reqID))\n\n\t\tres := &http.Response{\n\t\t\tRequest: req,\n\t\t\tHeader:  make(http.Header),\n\t\t}\n\t\tres.Header.Add(\"X-Foo\", \"foo\")\n\n\t\tvar modErr error\n\t\tvar wg sync.WaitGroup\n\t\twg.Add(1)\n\n\t\tnext := func(res *http.Response) error { return nil }\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tmodErr = svc.ResponseModifier(next)(res)\n\t\t}()\n\n\t\t// Wait shortly, to allow the res modifier goroutine to add `res` to the\n\t\t// array of intercepted responses.\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\tcancel()\n\n\t\tmodRes := *res\n\t\tmodRes.Header = make(http.Header)\n\t\tmodRes.Header.Set(\"X-Foo\", \"bar\")\n\n\t\terr := svc.ModifyResponse(reqID, &modRes)\n\t\tif !errors.Is(err, intercept.ErrRequestDone) {\n\t\t\tt.Fatalf(\"expected `intercept.ErrRequestDone`, got: %v\", err)\n\t\t}\n\n\t\twg.Wait()\n\n\t\tif !errors.Is(modErr, context.Canceled) {\n\t\t\tt.Fatalf(\"expected `context.Canceled`, got: %v\", modErr)\n\t\t}\n\t})\n\n\tt.Run(\"modify intercepted response\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\treq := httptest.NewRequest(\"GET\", \"https://example.com/foo\", nil)\n\t\treq.Header.Set(\"X-Foo\", \"foo\")\n\n\t\treqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\t\t*req = *req.WithContext(proxy.WithRequestID(req.Context(), reqID))\n\n\t\tres := &http.Response{\n\t\t\tRequest: req,\n\t\t\tHeader:  make(http.Header),\n\t\t}\n\t\tres.Header.Add(\"X-Foo\", \"foo\")\n\n\t\tmodRes := *res\n\t\tmodRes.Header = make(http.Header)\n\t\tmodRes.Header.Set(\"X-Foo\", \"bar\")\n\n\t\tlogger, _ := zap.NewDevelopment()\n\t\tsvc := intercept.NewService(intercept.Config{\n\t\t\tLogger:           logger.Sugar(),\n\t\t\tRequestsEnabled:  false,\n\t\t\tResponsesEnabled: true,\n\t\t})\n\n\t\tvar gotHeader string\n\n\t\tvar next proxy.ResponseModifyFunc = func(res *http.Response) error {\n\t\t\tgotHeader = res.Header.Get(\"X-Foo\")\n\t\t\treturn nil\n\t\t}\n\n\t\tvar modErr error\n\t\tvar wg sync.WaitGroup\n\t\twg.Add(1)\n\n\t\tgo func() {\n\t\t\tmodErr = svc.ResponseModifier(next)(res)\n\t\t\twg.Done()\n\t\t}()\n\n\t\t// Wait shortly, to allow the res modifier goroutine to add `req` to the\n\t\t// array of intercepted reqs.\n\t\ttime.Sleep(10 * time.Millisecond)\n\n\t\terr := svc.ModifyResponse(reqID, &modRes)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %v\", err)\n\t\t}\n\n\t\twg.Wait()\n\n\t\tif modErr != nil {\n\t\t\tt.Fatalf(\"unexpected error: %v\", modErr)\n\t\t}\n\n\t\tif exp := \"bar\"; exp != gotHeader {\n\t\t\tt.Fatalf(\"incorrect modified request header value (expected: %v, got: %v)\", exp, gotHeader)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "pkg/proxy/intercept/settings.go",
    "content": "package intercept\n\nimport \"github.com/dstotijn/hetty/pkg/filter\"\n\ntype Settings struct {\n\tRequestsEnabled  bool\n\tResponsesEnabled bool\n\tRequestFilter    filter.Expression\n\tResponseFilter   filter.Expression\n}\n"
  },
  {
    "path": "pkg/proxy/modify.go",
    "content": "package proxy\n\nimport \"net/http\"\n\nvar (\n\tnopReqModifier = func(req *http.Request) {}\n\tnopResModifier = func(res *http.Response) error { return nil }\n)\n\n// RequestModifyFunc defines a type for a function that can modify a HTTP\n// request before it's proxied.\ntype RequestModifyFunc func(req *http.Request)\n\n// RequestModifyMiddleware defines a type for chaining request modifier\n// middleware.\ntype RequestModifyMiddleware func(next RequestModifyFunc) RequestModifyFunc\n\n// ResponseModifyFunc defines a type for a function that can modify a HTTP\n// response before it's written back to the client.\ntype ResponseModifyFunc func(res *http.Response) error\n\n// ResponseModifyMiddleware defines a type for chaining response modifier\n// middleware.\ntype ResponseModifyMiddleware func(ResponseModifyFunc) ResponseModifyFunc\n"
  },
  {
    "path": "pkg/proxy/net.go",
    "content": "package proxy\n\nimport (\n\t\"errors\"\n\t\"net\"\n)\n\nvar ErrAlreadyAccepted = errors.New(\"listener already accepted\")\n\n// OnceListener implements net.Listener.\n//\n// Accepts a connection once and returns an error on subsequent\n// attempts.\ntype OnceAcceptListener struct {\n\tc net.Conn\n}\n\nfunc (l *OnceAcceptListener) Accept() (net.Conn, error) {\n\tif l.c == nil {\n\t\treturn nil, ErrAlreadyAccepted\n\t}\n\n\tc := l.c\n\tl.c = nil\n\n\treturn c, nil\n}\n\nfunc (l *OnceAcceptListener) Close() error {\n\treturn nil\n}\n\nfunc (l *OnceAcceptListener) Addr() net.Addr {\n\treturn l.c.LocalAddr()\n}\n\n// ConnNotify embeds net.Conn and adds a channel field for notifying\n// that the connection was closed.\ntype ConnNotify struct {\n\tnet.Conn\n\tclosed chan struct{}\n}\n\nfunc (c *ConnNotify) Close() {\n\tc.Conn.Close()\n\tc.closed <- struct{}{}\n}\n"
  },
  {
    "path": "pkg/proxy/proxy.go",
    "content": "package proxy\n\nimport (\n\t\"context\"\n\t\"crypto\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/oklog/ulid\"\n\n\t\"github.com/dstotijn/hetty/pkg/log\"\n)\n\n//nolint:gosec\nvar ulidEntropy = rand.New(rand.NewSource(time.Now().UnixNano()))\n\ntype contextKey int\n\nconst reqIDKey contextKey = 0\n\n// Proxy implements http.Handler and offers MITM behaviour for modifying\n// HTTP requests and responses.\ntype Proxy struct {\n\tcertConfig *CertConfig\n\thandler    http.Handler\n\tlogger     log.Logger\n\n\t// TODO: Add mutex for modifier funcs.\n\treqModifiers []RequestModifyMiddleware\n\tresModifiers []ResponseModifyMiddleware\n}\n\ntype Config struct {\n\tCACert *x509.Certificate\n\tCAKey  crypto.PrivateKey\n\tLogger log.Logger\n}\n\n// NewProxy returns a new Proxy.\nfunc NewProxy(cfg Config) (*Proxy, error) {\n\tcertConfig, err := NewCertConfig(cfg.CACert, cfg.CAKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tp := &Proxy{\n\t\tcertConfig:   certConfig,\n\t\treqModifiers: make([]RequestModifyMiddleware, 0),\n\t\tresModifiers: make([]ResponseModifyMiddleware, 0),\n\t\tlogger:       cfg.Logger,\n\t}\n\n\tif p.logger == nil {\n\t\tp.logger = log.NewNopLogger()\n\t}\n\n\ttransport := &http.Transport{\n\t\t// Values taken from `http.DefaultTransport`.\n\t\tProxy: http.ProxyFromEnvironment,\n\t\tDialContext: (&net.Dialer{\n\t\t\tTimeout:   30 * time.Second,\n\t\t\tKeepAlive: 30 * time.Second,\n\t\t}).DialContext,\n\t\tForceAttemptHTTP2:     true,\n\t\tMaxIdleConns:          100,\n\t\tIdleConnTimeout:       90 * time.Second,\n\t\tTLSHandshakeTimeout:   10 * time.Second,\n\t\tExpectContinueTimeout: 1 * time.Second,\n\n\t\t// Non-default transport values.\n\t\tDisableCompression: true,\n\t}\n\n\tp.handler = &httputil.ReverseProxy{\n\t\tTransport:      transport,\n\t\tDirector:       p.modifyRequest,\n\t\tModifyResponse: p.modifyResponse,\n\t\tErrorHandler:   p.errorHandler,\n\t}\n\n\treturn p, nil\n}\n\nfunc (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\tif r.Method == http.MethodConnect {\n\t\tp.handleConnect(w)\n\t\treturn\n\t}\n\n\treqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\tctx := context.WithValue(r.Context(), reqIDKey, reqID)\n\t*r = *r.WithContext(ctx)\n\n\tp.handler.ServeHTTP(w, r)\n}\n\nfunc (p *Proxy) UseRequestModifier(fn ...RequestModifyMiddleware) {\n\tp.reqModifiers = append(p.reqModifiers, fn...)\n}\n\nfunc (p *Proxy) UseResponseModifier(fn ...ResponseModifyMiddleware) {\n\tp.resModifiers = append(p.resModifiers, fn...)\n}\n\nfunc (p *Proxy) modifyRequest(r *http.Request) {\n\t// Fix r.URL for HTTPS requests after CONNECT.\n\tif r.URL.Scheme == \"\" {\n\t\tr.URL.Host = r.Host\n\t\tr.URL.Scheme = \"https\"\n\t}\n\n\t// Setting `X-Forwarded-For` to `nil` ensures that http.ReverseProxy doesn't\n\t// set this header.\n\tr.Header[\"X-Forwarded-For\"] = nil\n\n\t// Strip unsupported encodings.\n\tif acceptEncs := r.Header.Get(\"Accept-Encoding\"); acceptEncs != \"\" {\n\t\tdirectives := strings.Split(acceptEncs, \",\")\n\t\tupdated := make([]string, 0, len(directives))\n\n\t\tfor _, directive := range directives {\n\t\t\tstripped := strings.TrimSpace(directive)\n\t\t\tif strings.HasPrefix(stripped, \"*\") || strings.HasPrefix(stripped, \"gzip\") {\n\t\t\t\tupdated = append(updated, stripped)\n\t\t\t}\n\t\t}\n\n\t\tif len(updated) == 0 {\n\t\t\tr.Header.Del(\"Accept-Encoding\")\n\t\t} else {\n\t\t\tr.Header.Set(\"Accept-Encoding\", strings.Join(updated, \", \"))\n\t\t}\n\t}\n\n\tfn := nopReqModifier\n\n\tfor i := len(p.reqModifiers) - 1; i >= 0; i-- {\n\t\tfn = p.reqModifiers[i](fn)\n\t}\n\n\tfn(r)\n}\n\nfunc (p *Proxy) modifyResponse(res *http.Response) error {\n\tfn := nopResModifier\n\n\t// TODO: Make decompressing gzip formatted response bodies a configurable project setting.\n\tif err := gunzipResponseBody(res); err != nil {\n\t\treturn fmt.Errorf(\"proxy: failed to gunzip response body: %w\", err)\n\t}\n\n\tfor i := len(p.resModifiers) - 1; i >= 0; i-- {\n\t\tfn = p.resModifiers[i](fn)\n\t}\n\n\treturn fn(res)\n}\n\nfunc WithRequestID(ctx context.Context, id ulid.ULID) context.Context {\n\treturn context.WithValue(ctx, reqIDKey, id)\n}\n\nfunc RequestIDFromContext(ctx context.Context) (ulid.ULID, bool) {\n\tid, ok := ctx.Value(reqIDKey).(ulid.ULID)\n\treturn id, ok\n}\n\n// handleConnect hijacks the incoming HTTP request and sets up an HTTP tunnel.\n// During the TLS handshake with the client, we use the proxy's CA config to\n// create a certificate on-the-fly.\nfunc (p *Proxy) handleConnect(w http.ResponseWriter) {\n\thj, ok := w.(http.Hijacker)\n\tif !ok {\n\t\tp.logger.Errorw(\"ResponseWriter is not a http.Hijacker.\",\n\t\t\t\"type\", fmt.Sprintf(\"%T\", w))\n\t\twriteError(w, http.StatusServiceUnavailable)\n\n\t\treturn\n\t}\n\n\tw.WriteHeader(http.StatusOK)\n\n\tclientConn, _, err := hj.Hijack()\n\tif err != nil {\n\t\tp.logger.Errorw(\"Hijacking client connection failed.\",\n\t\t\t\"error\", err)\n\t\twriteError(w, http.StatusServiceUnavailable)\n\n\t\treturn\n\t}\n\tdefer clientConn.Close()\n\n\t// Secure connection to client.\n\ttlsConn, err := p.clientTLSConn(clientConn)\n\tif err != nil {\n\t\tp.logger.Errorw(\"Securing client connection failed.\",\n\t\t\t\"error\", err,\n\t\t\t\"remoteAddr\", clientConn.RemoteAddr().String())\n\n\t\treturn\n\t}\n\n\tclientConnNotify := ConnNotify{tlsConn, make(chan struct{})}\n\tl := &OnceAcceptListener{clientConnNotify.Conn}\n\n\terr = http.Serve(l, p)\n\tif err != nil && !errors.Is(err, ErrAlreadyAccepted) {\n\t\tp.logger.Errorw(\"Serving HTTP request failed.\",\n\t\t\t\"error\", err)\n\t}\n\n\t<-clientConnNotify.closed\n}\n\nfunc (p *Proxy) clientTLSConn(conn net.Conn) (*tls.Conn, error) {\n\ttlsConfig := p.certConfig.TLSConfig()\n\n\ttlsConn := tls.Server(conn, tlsConfig)\n\tif err := tlsConn.Handshake(); err != nil {\n\t\ttlsConn.Close()\n\t\treturn nil, fmt.Errorf(\"handshake error: %w\", err)\n\t}\n\n\treturn tlsConn, nil\n}\n\nfunc (p *Proxy) errorHandler(w http.ResponseWriter, r *http.Request, err error) {\n\tswitch {\n\tcase !errors.Is(err, context.Canceled):\n\t\tp.logger.Errorw(\"Failed to proxy request.\",\n\t\t\t\"error\", err)\n\tcase errors.Is(err, context.Canceled):\n\t\tp.logger.Debugw(\"Proxy request was cancelled.\")\n\t}\n\n\tw.WriteHeader(http.StatusBadGateway)\n}\n\nfunc writeError(w http.ResponseWriter, code int) {\n\thttp.Error(w, http.StatusText(code), code)\n}\n"
  },
  {
    "path": "pkg/reqlog/repo.go",
    "content": "package reqlog\n\nimport (\n\t\"context\"\n\n\t\"github.com/oklog/ulid\"\n\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n)\n\ntype Repository interface {\n\tFindRequestLogs(ctx context.Context, filter FindRequestsFilter, scope *scope.Scope) ([]RequestLog, error)\n\tFindRequestLogByID(ctx context.Context, projectID, id ulid.ULID) (RequestLog, error)\n\tStoreRequestLog(ctx context.Context, reqLog RequestLog) error\n\tStoreResponseLog(ctx context.Context, projectID, reqLogID ulid.ULID, resLog ResponseLog) error\n\tClearRequestLogs(ctx context.Context, projectID ulid.ULID) error\n}\n"
  },
  {
    "path": "pkg/reqlog/reqlog.go",
    "content": "package reqlog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"github.com/oklog/ulid\"\n\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n\t\"github.com/dstotijn/hetty/pkg/log\"\n\t\"github.com/dstotijn/hetty/pkg/proxy\"\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n)\n\ntype contextKey int\n\nconst (\n\tLogBypassedKey contextKey = iota\n\tReqLogIDKey\n)\n\nvar (\n\tErrRequestNotFound    = errors.New(\"reqlog: request not found\")\n\tErrProjectIDMustBeSet = errors.New(\"reqlog: project ID must be set\")\n)\n\ntype RequestLog struct {\n\tID        ulid.ULID\n\tProjectID ulid.ULID\n\n\tURL    *url.URL\n\tMethod string\n\tProto  string\n\tHeader http.Header\n\tBody   []byte\n\n\tResponse *ResponseLog\n}\n\ntype ResponseLog struct {\n\tProto      string\n\tStatusCode int\n\tStatus     string\n\tHeader     http.Header\n\tBody       []byte\n}\n\ntype Service struct {\n\tbypassOutOfScopeRequests bool\n\tfindReqsFilter           FindRequestsFilter\n\tactiveProjectID          ulid.ULID\n\tscope                    *scope.Scope\n\trepo                     Repository\n\tlogger                   log.Logger\n}\n\ntype FindRequestsFilter struct {\n\tProjectID   ulid.ULID\n\tOnlyInScope bool\n\tSearchExpr  filter.Expression\n}\n\ntype Config struct {\n\tActiveProjectID ulid.ULID\n\tScope           *scope.Scope\n\tRepository      Repository\n\tLogger          log.Logger\n}\n\nfunc NewService(cfg Config) *Service {\n\ts := &Service{\n\t\tactiveProjectID: cfg.ActiveProjectID,\n\t\trepo:            cfg.Repository,\n\t\tscope:           cfg.Scope,\n\t\tlogger:          cfg.Logger,\n\t}\n\n\tif s.logger == nil {\n\t\ts.logger = log.NewNopLogger()\n\t}\n\n\treturn s\n}\n\nfunc (svc *Service) FindRequests(ctx context.Context) ([]RequestLog, error) {\n\treturn svc.repo.FindRequestLogs(ctx, svc.findReqsFilter, svc.scope)\n}\n\nfunc (svc *Service) FindRequestLogByID(ctx context.Context, id ulid.ULID) (RequestLog, error) {\n\treturn svc.repo.FindRequestLogByID(ctx, svc.activeProjectID, id)\n}\n\nfunc (svc *Service) ClearRequests(ctx context.Context, projectID ulid.ULID) error {\n\treturn svc.repo.ClearRequestLogs(ctx, projectID)\n}\n\nfunc (svc *Service) storeResponse(ctx context.Context, reqLogID ulid.ULID, res *http.Response) error {\n\tresLog, err := ParseHTTPResponse(res)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn svc.repo.StoreResponseLog(ctx, svc.activeProjectID, reqLogID, resLog)\n}\n\nfunc (svc *Service) RequestModifier(next proxy.RequestModifyFunc) proxy.RequestModifyFunc {\n\treturn func(req *http.Request) {\n\t\tnext(req)\n\n\t\tclone := req.Clone(req.Context())\n\n\t\tvar body []byte\n\n\t\tif req.Body != nil {\n\t\t\t// TODO: Use io.LimitReader.\n\t\t\tvar err error\n\n\t\t\tbody, err = ioutil.ReadAll(req.Body)\n\t\t\tif err != nil {\n\t\t\t\tsvc.logger.Errorw(\"Failed to read request body for logging.\",\n\t\t\t\t\t\"error\", err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\treq.Body = ioutil.NopCloser(bytes.NewBuffer(body))\n\t\t\tclone.Body = ioutil.NopCloser(bytes.NewBuffer(body))\n\t\t}\n\n\t\t// Bypass logging if no project is active.\n\t\tif svc.activeProjectID.Compare(ulid.ULID{}) == 0 {\n\t\t\tctx := context.WithValue(req.Context(), LogBypassedKey, true)\n\t\t\t*req = *req.WithContext(ctx)\n\n\t\t\tsvc.logger.Debugw(\"Bypassed logging: no active project.\",\n\t\t\t\t\"url\", req.URL.String())\n\n\t\t\treturn\n\t\t}\n\n\t\t// Bypass logging if this setting is enabled and the incoming request\n\t\t// doesn't match any scope rules.\n\t\tif svc.bypassOutOfScopeRequests && !svc.scope.Match(clone, body) {\n\t\t\tctx := context.WithValue(req.Context(), LogBypassedKey, true)\n\t\t\t*req = *req.WithContext(ctx)\n\n\t\t\tsvc.logger.Debugw(\"Bypassed logging: request doesn't match any scope rules.\",\n\t\t\t\t\"url\", req.URL.String())\n\n\t\t\treturn\n\t\t}\n\n\t\treqID, ok := proxy.RequestIDFromContext(req.Context())\n\t\tif !ok {\n\t\t\tsvc.logger.Errorw(\"Bypassed logging: request doesn't have an ID.\")\n\t\t\treturn\n\t\t}\n\n\t\treqLog := RequestLog{\n\t\t\tID:        reqID,\n\t\t\tProjectID: svc.activeProjectID,\n\t\t\tMethod:    clone.Method,\n\t\t\tURL:       clone.URL,\n\t\t\tProto:     clone.Proto,\n\t\t\tHeader:    clone.Header,\n\t\t\tBody:      body,\n\t\t}\n\n\t\terr := svc.repo.StoreRequestLog(req.Context(), reqLog)\n\t\tif err != nil {\n\t\t\tsvc.logger.Errorw(\"Failed to store request log.\",\n\t\t\t\t\"error\", err)\n\t\t\treturn\n\t\t}\n\n\t\tsvc.logger.Debugw(\"Stored request log.\",\n\t\t\t\"reqLogID\", reqLog.ID.String(),\n\t\t\t\"url\", reqLog.URL.String())\n\n\t\tctx := context.WithValue(req.Context(), ReqLogIDKey, reqLog.ID)\n\t\t*req = *req.WithContext(ctx)\n\t}\n}\n\nfunc (svc *Service) ResponseModifier(next proxy.ResponseModifyFunc) proxy.ResponseModifyFunc {\n\treturn func(res *http.Response) error {\n\t\tif err := next(res); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif bypassed, _ := res.Request.Context().Value(LogBypassedKey).(bool); bypassed {\n\t\t\treturn nil\n\t\t}\n\n\t\treqLogID, ok := res.Request.Context().Value(ReqLogIDKey).(ulid.ULID)\n\t\tif !ok {\n\t\t\treturn errors.New(\"reqlog: request is missing ID\")\n\t\t}\n\n\t\tclone := *res\n\n\t\tif res.Body != nil {\n\t\t\t// TODO: Use io.LimitReader.\n\t\t\tbody, err := io.ReadAll(res.Body)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"reqlog: could not read response body: %w\", err)\n\t\t\t}\n\n\t\t\tres.Body = io.NopCloser(bytes.NewBuffer(body))\n\t\t\tclone.Body = io.NopCloser(bytes.NewBuffer(body))\n\t\t}\n\n\t\tgo func() {\n\t\t\tif err := svc.storeResponse(context.Background(), reqLogID, &clone); err != nil {\n\t\t\t\tsvc.logger.Errorw(\"Failed to store response log.\",\n\t\t\t\t\t\"error\", err)\n\t\t\t} else {\n\t\t\t\tsvc.logger.Debugw(\"Stored response log.\",\n\t\t\t\t\t\"reqLogID\", reqLogID.String())\n\t\t\t}\n\t\t}()\n\n\t\treturn nil\n\t}\n}\n\nfunc (svc *Service) SetActiveProjectID(id ulid.ULID) {\n\tsvc.activeProjectID = id\n}\n\nfunc (svc *Service) ActiveProjectID() ulid.ULID {\n\treturn svc.activeProjectID\n}\n\nfunc (svc *Service) SetFindReqsFilter(filter FindRequestsFilter) {\n\tsvc.findReqsFilter = filter\n}\n\nfunc (svc *Service) FindReqsFilter() FindRequestsFilter {\n\treturn svc.findReqsFilter\n}\n\nfunc (svc *Service) SetBypassOutOfScopeRequests(bypass bool) {\n\tsvc.bypassOutOfScopeRequests = bypass\n}\n\nfunc (svc *Service) BypassOutOfScopeRequests() bool {\n\treturn svc.bypassOutOfScopeRequests\n}\n\nfunc ParseHTTPResponse(res *http.Response) (ResponseLog, error) {\n\tbody, err := io.ReadAll(res.Body)\n\tif err != nil {\n\t\treturn ResponseLog{}, fmt.Errorf(\"reqlog: could not read body: %w\", err)\n\t}\n\n\treturn ResponseLog{\n\t\tProto:      res.Proto,\n\t\tStatusCode: res.StatusCode,\n\t\tStatus:     res.Status,\n\t\tHeader:     res.Header,\n\t\tBody:       body,\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/reqlog/reqlog_test.go",
    "content": "package reqlog_test\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/oklog/ulid\"\n\t\"go.etcd.io/bbolt\"\n\n\t\"github.com/dstotijn/hetty/pkg/db/bolt\"\n\t\"github.com/dstotijn/hetty/pkg/proj\"\n\t\"github.com/dstotijn/hetty/pkg/proxy\"\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n)\n\n//nolint:gosec\nvar ulidEntropy = rand.New(rand.NewSource(time.Now().UnixNano()))\n\n//nolint:paralleltest\nfunc TestRequestModifier(t *testing.T) {\n\tpath := t.TempDir() + \"bolt.db\"\n\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t}\n\tdefer boltDB.Close()\n\n\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t}\n\tdefer db.Close()\n\n\tprojectID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\terr = db.UpsertProject(context.Background(), proj.Project{\n\t\tID: projectID,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error upserting project: %v\", err)\n\t}\n\n\tsvc := reqlog.NewService(reqlog.Config{\n\t\tRepository: db,\n\t\tScope:      &scope.Scope{},\n\t})\n\tsvc.SetActiveProjectID(projectID)\n\n\tnext := func(req *http.Request) {\n\t\treq.Body = io.NopCloser(strings.NewReader(\"modified body\"))\n\t}\n\treqModFn := svc.RequestModifier(next)\n\treq := httptest.NewRequest(\"GET\", \"https://example.com/\", strings.NewReader(\"bar\"))\n\treqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\treq = req.WithContext(proxy.WithRequestID(req.Context(), reqID))\n\n\treqModFn(req)\n\n\tt.Run(\"request log was stored in repository\", func(t *testing.T) {\n\t\texp := reqlog.RequestLog{\n\t\t\tID:        reqID,\n\t\t\tProjectID: svc.ActiveProjectID(),\n\t\t\tMethod:    req.Method,\n\t\t\tURL:       req.URL,\n\t\t\tProto:     req.Proto,\n\t\t\tHeader:    req.Header,\n\t\t\tBody:      []byte(\"modified body\"),\n\t\t}\n\n\t\tgot, err := svc.FindRequestLogByID(context.Background(), reqID)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to find request by id: %v\", err)\n\t\t}\n\n\t\tif diff := cmp.Diff(exp, got); diff != \"\" {\n\t\t\tt.Fatalf(\"request log not equal (-exp, +got):\\n%v\", diff)\n\t\t}\n\t})\n}\n\n//nolint:paralleltest\nfunc TestResponseModifier(t *testing.T) {\n\tpath := t.TempDir() + \"bolt.db\"\n\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t}\n\tdefer boltDB.Close()\n\n\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t}\n\tdefer db.Close()\n\n\tprojectID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\terr = db.UpsertProject(context.Background(), proj.Project{\n\t\tID: projectID,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error upserting project: %v\", err)\n\t}\n\n\tsvc := reqlog.NewService(reqlog.Config{\n\t\tRepository: db,\n\t})\n\tsvc.SetActiveProjectID(projectID)\n\n\tnext := func(res *http.Response) error {\n\t\tres.Body = io.NopCloser(strings.NewReader(\"modified body\"))\n\t\treturn nil\n\t}\n\tresModFn := svc.ResponseModifier(next)\n\n\treq := httptest.NewRequest(\"GET\", \"https://example.com/\", strings.NewReader(\"bar\"))\n\treqLogID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\treq = req.WithContext(context.WithValue(req.Context(), reqlog.ReqLogIDKey, reqLogID))\n\n\terr = db.StoreRequestLog(context.Background(), reqlog.RequestLog{\n\t\tID:        reqLogID,\n\t\tProjectID: projectID,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"failed to store request log: %v\", err)\n\t}\n\n\tres := &http.Response{\n\t\tRequest: req,\n\t\tBody:    io.NopCloser(strings.NewReader(\"bar\")),\n\t}\n\n\tif err := resModFn(res); err != nil {\n\t\tt.Fatalf(\"unexpected error (expected: nil, got: %v)\", err)\n\t}\n\n\tt.Run(\"request log was stored in repository\", func(t *testing.T) {\n\t\t// Dirty (but simple) wait for other goroutine to finish calling repository.\n\t\ttime.Sleep(10 * time.Millisecond)\n\n\t\tgot, err := svc.FindRequestLogByID(context.Background(), reqLogID)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to find request by id: %v\", err)\n\t\t}\n\n\t\tt.Run(\"ran next modifier first, before calling repository\", func(t *testing.T) {\n\t\t\tif exp := \"modified body\"; exp != string(got.Response.Body) {\n\t\t\t\tt.Fatalf(\"incorrect `ResponseLog.Body` value (expected: %v, got: %v)\", exp, string(got.Response.Body))\n\t\t\t}\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "pkg/reqlog/search.go",
    "content": "package reqlog\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/oklog/ulid\"\n\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n)\n\nvar reqLogSearchKeyFns = map[string]func(rl RequestLog) string{\n\t\"req.id\":    func(rl RequestLog) string { return rl.ID.String() },\n\t\"req.proto\": func(rl RequestLog) string { return rl.Proto },\n\t\"req.url\": func(rl RequestLog) string {\n\t\tif rl.URL == nil {\n\t\t\treturn \"\"\n\t\t}\n\t\treturn rl.URL.String()\n\t},\n\t\"req.method\":    func(rl RequestLog) string { return rl.Method },\n\t\"req.body\":      func(rl RequestLog) string { return string(rl.Body) },\n\t\"req.timestamp\": func(rl RequestLog) string { return ulid.Time(rl.ID.Time()).String() },\n}\n\nvar ResLogSearchKeyFns = map[string]func(rl ResponseLog) string{\n\t\"res.proto\":        func(rl ResponseLog) string { return rl.Proto },\n\t\"res.statusCode\":   func(rl ResponseLog) string { return strconv.Itoa(rl.StatusCode) },\n\t\"res.statusReason\": func(rl ResponseLog) string { return rl.Status },\n\t\"res.body\":         func(rl ResponseLog) string { return string(rl.Body) },\n}\n\n// TODO: Request and response headers search key functions.\n\n// Matches returns true if the supplied search expression evaluates to true.\nfunc (reqLog RequestLog) Matches(expr filter.Expression) (bool, error) {\n\tswitch e := expr.(type) {\n\tcase filter.PrefixExpression:\n\t\treturn reqLog.matchPrefixExpr(e)\n\tcase filter.InfixExpression:\n\t\treturn reqLog.matchInfixExpr(e)\n\tcase filter.StringLiteral:\n\t\treturn reqLog.matchStringLiteral(e)\n\tdefault:\n\t\treturn false, fmt.Errorf(\"expression type (%T) not supported\", expr)\n\t}\n}\n\nfunc (reqLog RequestLog) matchPrefixExpr(expr filter.PrefixExpression) (bool, error) {\n\tswitch expr.Operator {\n\tcase filter.TokOpNot:\n\t\tmatch, err := reqLog.Matches(expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn !match, nil\n\tdefault:\n\t\treturn false, errors.New(\"operator is not supported\")\n\t}\n}\n\nfunc (reqLog RequestLog) matchInfixExpr(expr filter.InfixExpression) (bool, error) {\n\tswitch expr.Operator {\n\tcase filter.TokOpAnd:\n\t\tleft, err := reqLog.Matches(expr.Left)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tright, err := reqLog.Matches(expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn left && right, nil\n\tcase filter.TokOpOr:\n\t\tleft, err := reqLog.Matches(expr.Left)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tright, err := reqLog.Matches(expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn left || right, nil\n\t}\n\n\tleft, ok := expr.Left.(filter.StringLiteral)\n\tif !ok {\n\t\treturn false, errors.New(\"left operand must be a string literal\")\n\t}\n\n\tleftVal := reqLog.getMappedStringLiteral(left.Value)\n\n\tif leftVal == \"req.headers\" {\n\t\tmatch, err := filter.MatchHTTPHeaders(expr.Operator, expr.Right, reqLog.Header)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to match request HTTP headers: %w\", err)\n\t\t}\n\n\t\treturn match, nil\n\t}\n\n\tif leftVal == \"res.headers\" && reqLog.Response != nil {\n\t\tmatch, err := filter.MatchHTTPHeaders(expr.Operator, expr.Right, reqLog.Response.Header)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to match response HTTP headers: %w\", err)\n\t\t}\n\n\t\treturn match, nil\n\t}\n\n\tif expr.Operator == filter.TokOpRe || expr.Operator == filter.TokOpNotRe {\n\t\tright, ok := expr.Right.(filter.RegexpLiteral)\n\t\tif !ok {\n\t\t\treturn false, errors.New(\"right operand must be a regular expression\")\n\t\t}\n\n\t\tswitch expr.Operator {\n\t\tcase filter.TokOpRe:\n\t\t\treturn right.MatchString(leftVal), nil\n\t\tcase filter.TokOpNotRe:\n\t\t\treturn !right.MatchString(leftVal), nil\n\t\t}\n\t}\n\n\tright, ok := expr.Right.(filter.StringLiteral)\n\tif !ok {\n\t\treturn false, errors.New(\"right operand must be a string literal\")\n\t}\n\n\trightVal := reqLog.getMappedStringLiteral(right.Value)\n\n\tswitch expr.Operator {\n\tcase filter.TokOpEq:\n\t\treturn leftVal == rightVal, nil\n\tcase filter.TokOpNotEq:\n\t\treturn leftVal != rightVal, nil\n\tcase filter.TokOpGt:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal > rightVal, nil\n\tcase filter.TokOpLt:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal < rightVal, nil\n\tcase filter.TokOpGtEq:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal >= rightVal, nil\n\tcase filter.TokOpLtEq:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal <= rightVal, nil\n\tdefault:\n\t\treturn false, errors.New(\"unsupported operator\")\n\t}\n}\n\nfunc (reqLog RequestLog) getMappedStringLiteral(s string) string {\n\tswitch {\n\tcase strings.HasPrefix(s, \"req.\"):\n\t\tfn, ok := reqLogSearchKeyFns[s]\n\t\tif ok {\n\t\t\treturn fn(reqLog)\n\t\t}\n\tcase strings.HasPrefix(s, \"res.\"):\n\t\tif reqLog.Response == nil {\n\t\t\treturn \"\"\n\t\t}\n\n\t\tfn, ok := ResLogSearchKeyFns[s]\n\t\tif ok {\n\t\t\treturn fn(*reqLog.Response)\n\t\t}\n\t}\n\n\treturn s\n}\n\nfunc (reqLog RequestLog) matchStringLiteral(strLiteral filter.StringLiteral) (bool, error) {\n\tfor key, values := range reqLog.Header {\n\t\tfor _, value := range values {\n\t\t\tif strings.Contains(\n\t\t\t\tstrings.ToLower(fmt.Sprintf(\"%v: %v\", key, value)),\n\t\t\t\tstrings.ToLower(strLiteral.Value),\n\t\t\t) {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, fn := range reqLogSearchKeyFns {\n\t\tif strings.Contains(\n\t\t\tstrings.ToLower(fn(reqLog)),\n\t\t\tstrings.ToLower(strLiteral.Value),\n\t\t) {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\n\tif reqLog.Response != nil {\n\t\tfor key, values := range reqLog.Response.Header {\n\t\t\tfor _, value := range values {\n\t\t\t\tif strings.Contains(\n\t\t\t\t\tstrings.ToLower(fmt.Sprintf(\"%v: %v\", key, value)),\n\t\t\t\t\tstrings.ToLower(strLiteral.Value),\n\t\t\t\t) {\n\t\t\t\t\treturn true, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor _, fn := range ResLogSearchKeyFns {\n\t\t\tif strings.Contains(\n\t\t\t\tstrings.ToLower(fn(*reqLog.Response)),\n\t\t\t\tstrings.ToLower(strLiteral.Value),\n\t\t\t) {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false, nil\n}\n\nfunc (reqLog RequestLog) MatchScope(s *scope.Scope) bool {\n\tfor _, rule := range s.Rules() {\n\t\tif rule.URL != nil && reqLog.URL != nil {\n\t\t\tif matches := rule.URL.MatchString(reqLog.URL.String()); matches {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tfor key, values := range reqLog.Header {\n\t\t\tvar keyMatches, valueMatches bool\n\n\t\t\tif rule.Header.Key != nil {\n\t\t\t\tif matches := rule.Header.Key.MatchString(key); matches {\n\t\t\t\t\tkeyMatches = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif rule.Header.Value != nil {\n\t\t\t\tfor _, value := range values {\n\t\t\t\t\tif matches := rule.Header.Value.MatchString(value); matches {\n\t\t\t\t\t\tvalueMatches = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// When only key or value is set, match on whatever is set.\n\t\t\t// When both are set, both must match.\n\t\t\tswitch {\n\t\t\tcase rule.Header.Key != nil && rule.Header.Value == nil && keyMatches:\n\t\t\t\treturn true\n\t\t\tcase rule.Header.Key == nil && rule.Header.Value != nil && valueMatches:\n\t\t\t\treturn true\n\t\t\tcase rule.Header.Key != nil && rule.Header.Value != nil && keyMatches && valueMatches:\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tif rule.Body != nil {\n\t\t\tif matches := rule.Body.Match(reqLog.Body); matches {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "pkg/reqlog/search_test.go",
    "content": "package reqlog_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n)\n\nfunc TestRequestLogMatch(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname          string\n\t\tquery         string\n\t\trequestLog    reqlog.RequestLog\n\t\texpectedMatch bool\n\t\texpectedError error\n\t}{\n\t\t{\n\t\t\tname:  \"infix expression, equal operator, match\",\n\t\t\tquery: \"req.body = foo\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, not equal operator, match\",\n\t\t\tquery: \"req.body != bar\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, greater than operator, match\",\n\t\t\tquery: \"req.body > a\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"b\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, less than operator, match\",\n\t\t\tquery: \"req.body < b\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"a\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, greater than or equal operator, match greater than\",\n\t\t\tquery: \"req.body >= a\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"b\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, greater than or equal operator, match equal\",\n\t\t\tquery: \"req.body >= a\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"a\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, less than or equal operator, match less than\",\n\t\t\tquery: \"req.body <= b\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"a\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, less than or equal operator, match equal\",\n\t\t\tquery: \"req.body <= b\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"b\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, regular expression operator, match\",\n\t\t\tquery: `req.body =~ \"^foo(.*)$\"`,\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"foobar\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, negate regular expression operator, match\",\n\t\t\tquery: `req.body !~ \"^foo(.*)$\"`,\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"xoobar\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, and operator, match\",\n\t\t\tquery: \"req.body = bar AND res.body = yolo\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"bar\"),\n\t\t\t\tResponse: &reqlog.ResponseLog{\n\t\t\t\t\tBody: []byte(\"yolo\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, or operator, match\",\n\t\t\tquery: \"req.body = bar OR res.body = yolo\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t\tResponse: &reqlog.ResponseLog{\n\t\t\t\t\tBody: []byte(\"yolo\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"prefix expression, not operator, match\",\n\t\t\tquery: \"NOT (req.body = bar)\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"string literal expression, match in request log\",\n\t\t\tquery: \"foo\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"string literal expression, no match\",\n\t\t\tquery: \"foo\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tBody: []byte(\"bar\"),\n\t\t\t},\n\t\t\texpectedMatch: false,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"string literal expression, match in response log\",\n\t\t\tquery: \"foo\",\n\t\t\trequestLog: reqlog.RequestLog{\n\t\t\t\tResponse: &reqlog.ResponseLog{\n\t\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\ttt := tt\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsearchExpr, err := filter.ParseQuery(tt.query)\n\t\t\tassertError(t, nil, err)\n\n\t\t\tgot, err := tt.requestLog.Matches(searchExpr)\n\t\t\tassertError(t, tt.expectedError, err)\n\n\t\t\tif tt.expectedMatch != got {\n\t\t\t\tt.Errorf(\"expected match result: %v, got: %v\", tt.expectedMatch, got)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc assertError(t *testing.T, exp, got error) {\n\tt.Helper()\n\n\tswitch {\n\tcase exp == nil && got != nil:\n\t\tt.Fatalf(\"expected: nil, got: %v\", got)\n\tcase exp != nil && got == nil:\n\t\tt.Fatalf(\"expected: %v, got: nil\", exp.Error())\n\tcase exp != nil && got != nil && exp.Error() != got.Error():\n\t\tt.Fatalf(\"expected: %v, got: %v\", exp.Error(), got.Error())\n\t}\n}\n"
  },
  {
    "path": "pkg/scope/scope.go",
    "content": "package scope\n\nimport (\n\t\"bytes\"\n\t\"encoding/gob\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"sync\"\n)\n\ntype Scope struct {\n\trules []Rule\n\tmu    sync.RWMutex\n}\n\ntype Rule struct {\n\tURL    *regexp.Regexp\n\tHeader Header\n\tBody   *regexp.Regexp\n}\n\ntype Header struct {\n\tKey   *regexp.Regexp\n\tValue *regexp.Regexp\n}\n\nfunc (s *Scope) Rules() []Rule {\n\ts.mu.RLock()\n\tdefer s.mu.RUnlock()\n\n\treturn s.rules\n}\n\nfunc (s *Scope) SetRules(rules []Rule) {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\ts.rules = rules\n}\n\nfunc (s *Scope) Match(req *http.Request, body []byte) bool {\n\ts.mu.RLock()\n\tdefer s.mu.RUnlock()\n\n\tfor _, rule := range s.rules {\n\t\tif matches := rule.Match(req, body); matches {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (r Rule) Match(req *http.Request, body []byte) bool {\n\tif r.URL != nil {\n\t\tif matches := r.URL.MatchString(req.URL.String()); matches {\n\t\t\treturn true\n\t\t}\n\t}\n\n\tfor key, values := range req.Header {\n\t\tvar keyMatches, valueMatches bool\n\n\t\tif r.Header.Key != nil {\n\t\t\tif matches := r.Header.Key.MatchString(key); matches {\n\t\t\t\tkeyMatches = true\n\t\t\t}\n\t\t}\n\n\t\tif r.Header.Value != nil {\n\t\t\tfor _, value := range values {\n\t\t\t\tif matches := r.Header.Value.MatchString(value); matches {\n\t\t\t\t\tvalueMatches = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// When only key or value is set, match on whatever is set.\n\t\t// When both are set, both must match.\n\t\tswitch {\n\t\tcase r.Header.Key != nil && r.Header.Value == nil && keyMatches:\n\t\t\treturn true\n\t\tcase r.Header.Key == nil && r.Header.Value != nil && valueMatches:\n\t\t\treturn true\n\t\tcase r.Header.Key != nil && r.Header.Value != nil && keyMatches && valueMatches:\n\t\t\treturn true\n\t\t}\n\t}\n\n\tif r.Body != nil {\n\t\tif matches := r.Body.Match(body); matches {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc regexpToString(r *regexp.Regexp) string {\n\tif r == nil {\n\t\treturn \"\"\n\t}\n\n\treturn r.String()\n}\n\nfunc stringToRegexp(s string) (*regexp.Regexp, error) {\n\tif s == \"\" {\n\t\treturn nil, nil\n\t}\n\n\treturn regexp.Compile(s)\n}\n\ntype ruleDTO struct {\n\tURL    string\n\tHeader struct {\n\t\tKey   string\n\t\tValue string\n\t}\n\tBody string\n}\n\nfunc (r Rule) MarshalBinary() ([]byte, error) {\n\tdto := ruleDTO{\n\t\tURL:  regexpToString(r.URL),\n\t\tBody: regexpToString(r.Body),\n\t}\n\tdto.Header.Key = regexpToString(r.Header.Key)\n\tdto.Header.Value = regexpToString(r.Header.Value)\n\n\tbuf := bytes.Buffer{}\n\n\terr := gob.NewEncoder(&buf).Encode(dto)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn buf.Bytes(), nil\n}\n\nfunc (r *Rule) UnmarshalBinary(data []byte) error {\n\tdto := ruleDTO{}\n\n\terr := gob.NewDecoder(bytes.NewReader(data)).Decode(&dto)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\turl, err := stringToRegexp(dto.URL)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\theaderKey, err := stringToRegexp(dto.Header.Key)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\theaderValue, err := stringToRegexp(dto.Header.Value)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tbody, err := stringToRegexp(dto.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*r = Rule{\n\t\tURL: url,\n\t\tHeader: Header{\n\t\t\tKey:   headerKey,\n\t\t\tValue: headerValue,\n\t\t},\n\t\tBody: body,\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/sender/repo.go",
    "content": "package sender\n\nimport (\n\t\"context\"\n\n\t\"github.com/oklog/ulid\"\n\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n)\n\ntype Repository interface {\n\tFindSenderRequestByID(ctx context.Context, projectID, id ulid.ULID) (Request, error)\n\tFindSenderRequests(ctx context.Context, filter FindRequestsFilter, scope *scope.Scope) ([]Request, error)\n\tStoreSenderRequest(ctx context.Context, req Request) error\n\tDeleteSenderRequests(ctx context.Context, projectID ulid.ULID) error\n}\n"
  },
  {
    "path": "pkg/sender/search.go",
    "content": "package sender\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/oklog/ulid\"\n\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n)\n\nvar senderReqSearchKeyFns = map[string]func(req Request) string{\n\t\"req.id\":    func(req Request) string { return req.ID.String() },\n\t\"req.proto\": func(req Request) string { return req.Proto },\n\t\"req.url\": func(req Request) string {\n\t\tif req.URL == nil {\n\t\t\treturn \"\"\n\t\t}\n\t\treturn req.URL.String()\n\t},\n\t\"req.method\":    func(req Request) string { return req.Method },\n\t\"req.body\":      func(req Request) string { return string(req.Body) },\n\t\"req.timestamp\": func(req Request) string { return ulid.Time(req.ID.Time()).String() },\n}\n\n// TODO: Request and response headers search key functions.\n\n// Matches returns true if the supplied search expression evaluates to true.\nfunc (req Request) Matches(expr filter.Expression) (bool, error) {\n\tswitch e := expr.(type) {\n\tcase filter.PrefixExpression:\n\t\treturn req.matchPrefixExpr(e)\n\tcase filter.InfixExpression:\n\t\treturn req.matchInfixExpr(e)\n\tcase filter.StringLiteral:\n\t\treturn req.matchStringLiteral(e)\n\tdefault:\n\t\treturn false, fmt.Errorf(\"expression type (%T) not supported\", expr)\n\t}\n}\n\nfunc (req Request) matchPrefixExpr(expr filter.PrefixExpression) (bool, error) {\n\tswitch expr.Operator {\n\tcase filter.TokOpNot:\n\t\tmatch, err := req.Matches(expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn !match, nil\n\tdefault:\n\t\treturn false, errors.New(\"operator is not supported\")\n\t}\n}\n\nfunc (req Request) matchInfixExpr(expr filter.InfixExpression) (bool, error) {\n\tswitch expr.Operator {\n\tcase filter.TokOpAnd:\n\t\tleft, err := req.Matches(expr.Left)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tright, err := req.Matches(expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn left && right, nil\n\tcase filter.TokOpOr:\n\t\tleft, err := req.Matches(expr.Left)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tright, err := req.Matches(expr.Right)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn left || right, nil\n\t}\n\n\tleft, ok := expr.Left.(filter.StringLiteral)\n\tif !ok {\n\t\treturn false, errors.New(\"left operand must be a string literal\")\n\t}\n\n\tleftVal := req.getMappedStringLiteral(left.Value)\n\n\tif leftVal == \"req.headers\" {\n\t\tmatch, err := filter.MatchHTTPHeaders(expr.Operator, expr.Right, req.Header)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to match request HTTP headers: %w\", err)\n\t\t}\n\n\t\treturn match, nil\n\t}\n\n\tif leftVal == \"res.headers\" && req.Response != nil {\n\t\tmatch, err := filter.MatchHTTPHeaders(expr.Operator, expr.Right, req.Response.Header)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to match response HTTP headers: %w\", err)\n\t\t}\n\n\t\treturn match, nil\n\t}\n\n\tif expr.Operator == filter.TokOpRe || expr.Operator == filter.TokOpNotRe {\n\t\tright, ok := expr.Right.(filter.RegexpLiteral)\n\t\tif !ok {\n\t\t\treturn false, errors.New(\"right operand must be a regular expression\")\n\t\t}\n\n\t\tswitch expr.Operator {\n\t\tcase filter.TokOpRe:\n\t\t\treturn right.MatchString(leftVal), nil\n\t\tcase filter.TokOpNotRe:\n\t\t\treturn !right.MatchString(leftVal), nil\n\t\t}\n\t}\n\n\tright, ok := expr.Right.(filter.StringLiteral)\n\tif !ok {\n\t\treturn false, errors.New(\"right operand must be a string literal\")\n\t}\n\n\trightVal := req.getMappedStringLiteral(right.Value)\n\n\tswitch expr.Operator {\n\tcase filter.TokOpEq:\n\t\treturn leftVal == rightVal, nil\n\tcase filter.TokOpNotEq:\n\t\treturn leftVal != rightVal, nil\n\tcase filter.TokOpGt:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal > rightVal, nil\n\tcase filter.TokOpLt:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal < rightVal, nil\n\tcase filter.TokOpGtEq:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal >= rightVal, nil\n\tcase filter.TokOpLtEq:\n\t\t// TODO(?) attempt to parse as int.\n\t\treturn leftVal <= rightVal, nil\n\tdefault:\n\t\treturn false, errors.New(\"unsupported operator\")\n\t}\n}\n\nfunc (req Request) getMappedStringLiteral(s string) string {\n\tswitch {\n\tcase strings.HasPrefix(s, \"req.\"):\n\t\tfn, ok := senderReqSearchKeyFns[s]\n\t\tif ok {\n\t\t\treturn fn(req)\n\t\t}\n\tcase strings.HasPrefix(s, \"res.\"):\n\t\tif req.Response == nil {\n\t\t\treturn \"\"\n\t\t}\n\n\t\tfn, ok := reqlog.ResLogSearchKeyFns[s]\n\t\tif ok {\n\t\t\treturn fn(*req.Response)\n\t\t}\n\t}\n\n\treturn s\n}\n\nfunc (req Request) matchStringLiteral(strLiteral filter.StringLiteral) (bool, error) {\n\tfor key, values := range req.Header {\n\t\tfor _, value := range values {\n\t\t\tif strings.Contains(\n\t\t\t\tstrings.ToLower(fmt.Sprintf(\"%v: %v\", key, value)),\n\t\t\t\tstrings.ToLower(strLiteral.Value),\n\t\t\t) {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, fn := range senderReqSearchKeyFns {\n\t\tif strings.Contains(\n\t\t\tstrings.ToLower(fn(req)),\n\t\t\tstrings.ToLower(strLiteral.Value),\n\t\t) {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\n\tif req.Response != nil {\n\t\tfor key, values := range req.Response.Header {\n\t\t\tfor _, value := range values {\n\t\t\t\tif strings.Contains(\n\t\t\t\t\tstrings.ToLower(fmt.Sprintf(\"%v: %v\", key, value)),\n\t\t\t\t\tstrings.ToLower(strLiteral.Value),\n\t\t\t\t) {\n\t\t\t\t\treturn true, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor _, fn := range reqlog.ResLogSearchKeyFns {\n\t\t\tif strings.Contains(\n\t\t\t\tstrings.ToLower(fn(*req.Response)),\n\t\t\t\tstrings.ToLower(strLiteral.Value),\n\t\t\t) {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false, nil\n}\n\nfunc (req Request) MatchScope(s *scope.Scope) bool {\n\tfor _, rule := range s.Rules() {\n\t\tif rule.URL != nil && req.URL != nil {\n\t\t\tif matches := rule.URL.MatchString(req.URL.String()); matches {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tfor key, values := range req.Header {\n\t\t\tvar keyMatches, valueMatches bool\n\n\t\t\tif rule.Header.Key != nil {\n\t\t\t\tif matches := rule.Header.Key.MatchString(key); matches {\n\t\t\t\t\tkeyMatches = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif rule.Header.Value != nil {\n\t\t\t\tfor _, value := range values {\n\t\t\t\t\tif matches := rule.Header.Value.MatchString(value); matches {\n\t\t\t\t\t\tvalueMatches = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// When only key or value is set, match on whatever is set.\n\t\t\t// When both are set, both must match.\n\t\t\tswitch {\n\t\t\tcase rule.Header.Key != nil && rule.Header.Value == nil && keyMatches:\n\t\t\t\treturn true\n\t\t\tcase rule.Header.Key == nil && rule.Header.Value != nil && valueMatches:\n\t\t\t\treturn true\n\t\t\tcase rule.Header.Key != nil && rule.Header.Value != nil && keyMatches && valueMatches:\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tif rule.Body != nil {\n\t\t\tif matches := rule.Body.Match(req.Body); matches {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "pkg/sender/search_test.go",
    "content": "package sender_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n\t\"github.com/dstotijn/hetty/pkg/sender\"\n)\n\nfunc TestRequestLogMatch(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname          string\n\t\tquery         string\n\t\tsenderReq     sender.Request\n\t\texpectedMatch bool\n\t\texpectedError error\n\t}{\n\t\t{\n\t\t\tname:  \"infix expression, equal operator, match\",\n\t\t\tquery: \"req.body = foo\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, not equal operator, match\",\n\t\t\tquery: \"req.body != bar\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, greater than operator, match\",\n\t\t\tquery: \"req.body > a\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"b\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, less than operator, match\",\n\t\t\tquery: \"req.body < b\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"a\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, greater than or equal operator, match greater than\",\n\t\t\tquery: \"req.body >= a\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"b\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, greater than or equal operator, match equal\",\n\t\t\tquery: \"req.body >= a\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"a\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, less than or equal operator, match less than\",\n\t\t\tquery: \"req.body <= b\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"a\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, less than or equal operator, match equal\",\n\t\t\tquery: \"req.body <= b\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"b\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, regular expression operator, match\",\n\t\t\tquery: `req.body =~ \"^foo(.*)$\"`,\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"foobar\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, negate regular expression operator, match\",\n\t\t\tquery: `req.body !~ \"^foo(.*)$\"`,\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"xoobar\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, and operator, match\",\n\t\t\tquery: \"req.body = bar AND res.body = yolo\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"bar\"),\n\t\t\t\tResponse: &reqlog.ResponseLog{\n\t\t\t\t\tBody: []byte(\"yolo\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"infix expression, or operator, match\",\n\t\t\tquery: \"req.body = bar OR res.body = yolo\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t\tResponse: &reqlog.ResponseLog{\n\t\t\t\t\tBody: []byte(\"yolo\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"prefix expression, not operator, match\",\n\t\t\tquery: \"NOT (req.body = bar)\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"string literal expression, match in request log\",\n\t\t\tquery: \"foo\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"string literal expression, no match\",\n\t\t\tquery: \"foo\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tBody: []byte(\"bar\"),\n\t\t\t},\n\t\t\texpectedMatch: false,\n\t\t\texpectedError: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"string literal expression, match in response log\",\n\t\t\tquery: \"foo\",\n\t\t\tsenderReq: sender.Request{\n\t\t\t\tResponse: &reqlog.ResponseLog{\n\t\t\t\t\tBody: []byte(\"foo\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedMatch: true,\n\t\t\texpectedError: nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\ttt := tt\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsearchExpr, err := filter.ParseQuery(tt.query)\n\t\t\tassertError(t, nil, err)\n\n\t\t\tgot, err := tt.senderReq.Matches(searchExpr)\n\t\t\tassertError(t, tt.expectedError, err)\n\n\t\t\tif tt.expectedMatch != got {\n\t\t\t\tt.Errorf(\"expected match result: %v, got: %v\", tt.expectedMatch, got)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc assertError(t *testing.T, exp, got error) {\n\tt.Helper()\n\n\tswitch {\n\tcase exp == nil && got != nil:\n\t\tt.Fatalf(\"expected: nil, got: %v\", got)\n\tcase exp != nil && got == nil:\n\t\tt.Fatalf(\"expected: %v, got: nil\", exp.Error())\n\tcase exp != nil && got != nil && exp.Error() != got.Error():\n\t\tt.Fatalf(\"expected: %v, got: %v\", exp.Error(), got.Error())\n\t}\n}\n"
  },
  {
    "path": "pkg/sender/sender.go",
    "content": "package sender\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/oklog/ulid\"\n\n\t\"github.com/dstotijn/hetty/pkg/filter\"\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n\t\"github.com/dstotijn/hetty/pkg/scope\"\n)\n\n//nolint:gosec\nvar ulidEntropy = rand.New(rand.NewSource(time.Now().UnixNano()))\n\nvar defaultHTTPClient = &http.Client{\n\tTransport: &HTTPTransport{},\n\tTimeout:   30 * time.Second,\n}\n\nvar (\n\tErrProjectIDMustBeSet = errors.New(\"sender: project ID must be set\")\n\tErrRequestNotFound    = errors.New(\"sender: request not found\")\n)\n\ntype Service struct {\n\tactiveProjectID ulid.ULID\n\tfindReqsFilter  FindRequestsFilter\n\tscope           *scope.Scope\n\trepo            Repository\n\treqLogSvc       *reqlog.Service\n\thttpClient      *http.Client\n}\n\ntype FindRequestsFilter struct {\n\tProjectID   ulid.ULID\n\tOnlyInScope bool\n\tSearchExpr  filter.Expression\n}\n\ntype Config struct {\n\tScope         *scope.Scope\n\tRepository    Repository\n\tReqLogService *reqlog.Service\n\tHTTPClient    *http.Client\n}\n\ntype SendError struct {\n\terr error\n}\n\nfunc NewService(cfg Config) *Service {\n\tsvc := &Service{\n\t\trepo:       cfg.Repository,\n\t\treqLogSvc:  cfg.ReqLogService,\n\t\thttpClient: defaultHTTPClient,\n\t\tscope:      cfg.Scope,\n\t}\n\n\tif cfg.HTTPClient != nil {\n\t\tsvc.httpClient = cfg.HTTPClient\n\t}\n\n\treturn svc\n}\n\ntype Request struct {\n\tID                 ulid.ULID\n\tProjectID          ulid.ULID\n\tSourceRequestLogID ulid.ULID\n\n\tURL    *url.URL\n\tMethod string\n\tProto  string\n\tHeader http.Header\n\tBody   []byte\n\n\tResponse *reqlog.ResponseLog\n}\n\nfunc (svc *Service) FindRequestByID(ctx context.Context, id ulid.ULID) (Request, error) {\n\treq, err := svc.repo.FindSenderRequestByID(ctx, svc.activeProjectID, id)\n\tif err != nil {\n\t\treturn Request{}, fmt.Errorf(\"sender: failed to find request: %w\", err)\n\t}\n\n\treturn req, nil\n}\n\nfunc (svc *Service) FindRequests(ctx context.Context) ([]Request, error) {\n\treturn svc.repo.FindSenderRequests(ctx, svc.findReqsFilter, svc.scope)\n}\n\nfunc (svc *Service) CreateOrUpdateRequest(ctx context.Context, req Request) (Request, error) {\n\tif svc.activeProjectID.Compare(ulid.ULID{}) == 0 {\n\t\treturn Request{}, ErrProjectIDMustBeSet\n\t}\n\n\tif req.ID.Compare(ulid.ULID{}) == 0 {\n\t\treq.ID = ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\t}\n\n\treq.ProjectID = svc.activeProjectID\n\n\tif req.Method == \"\" {\n\t\treq.Method = http.MethodGet\n\t}\n\n\tif req.Proto == \"\" {\n\t\treq.Proto = HTTPProto20\n\t}\n\n\tif !isValidProto(req.Proto) {\n\t\treturn Request{}, fmt.Errorf(\"sender: unsupported HTTP protocol: %v\", req.Proto)\n\t}\n\n\terr := svc.repo.StoreSenderRequest(ctx, req)\n\tif err != nil {\n\t\treturn Request{}, fmt.Errorf(\"sender: failed to store request: %w\", err)\n\t}\n\n\treturn req, nil\n}\n\nfunc (svc *Service) CloneFromRequestLog(ctx context.Context, reqLogID ulid.ULID) (Request, error) {\n\tif svc.activeProjectID.Compare(ulid.ULID{}) == 0 {\n\t\treturn Request{}, ErrProjectIDMustBeSet\n\t}\n\n\treqLog, err := svc.reqLogSvc.FindRequestLogByID(ctx, reqLogID)\n\tif err != nil {\n\t\treturn Request{}, fmt.Errorf(\"sender: failed to find request log: %w\", err)\n\t}\n\n\treq := Request{\n\t\tID:                 ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy),\n\t\tProjectID:          svc.activeProjectID,\n\t\tSourceRequestLogID: reqLogID,\n\t\tMethod:             reqLog.Method,\n\t\tURL:                reqLog.URL,\n\t\tProto:              HTTPProto20, // Attempt HTTP/2.\n\t\tHeader:             reqLog.Header,\n\t\tBody:               reqLog.Body,\n\t}\n\n\terr = svc.repo.StoreSenderRequest(ctx, req)\n\tif err != nil {\n\t\treturn Request{}, fmt.Errorf(\"sender: failed to store request: %w\", err)\n\t}\n\n\treturn req, nil\n}\n\nfunc (svc *Service) SetFindReqsFilter(filter FindRequestsFilter) {\n\tsvc.findReqsFilter = filter\n}\n\nfunc (svc *Service) FindReqsFilter() FindRequestsFilter {\n\treturn svc.findReqsFilter\n}\n\nfunc (svc *Service) SendRequest(ctx context.Context, id ulid.ULID) (Request, error) {\n\treq, err := svc.repo.FindSenderRequestByID(ctx, svc.activeProjectID, id)\n\tif err != nil {\n\t\treturn Request{}, fmt.Errorf(\"sender: failed to find request: %w\", err)\n\t}\n\n\thttpReq, err := parseHTTPRequest(ctx, req)\n\tif err != nil {\n\t\treturn Request{}, fmt.Errorf(\"sender: failed to parse HTTP request: %w\", err)\n\t}\n\n\tresLog, err := svc.sendHTTPRequest(httpReq)\n\tif err != nil {\n\t\treturn Request{}, fmt.Errorf(\"sender: could not send HTTP request: %w\", err)\n\t}\n\n\treq.Response = &resLog\n\n\terr = svc.repo.StoreSenderRequest(ctx, req)\n\tif err != nil {\n\t\treturn Request{}, fmt.Errorf(\"sender: failed to store sender response log: %w\", err)\n\t}\n\n\treq.Response = &resLog\n\n\treturn req, nil\n}\n\nfunc parseHTTPRequest(ctx context.Context, req Request) (*http.Request, error) {\n\tctx = context.WithValue(ctx, protoCtxKey{}, req.Proto)\n\n\thttpReq, err := http.NewRequestWithContext(ctx, req.Method, req.URL.String(), bytes.NewReader(req.Body))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to construct HTTP request: %w\", err)\n\t}\n\n\tif req.Header != nil {\n\t\thttpReq.Header = req.Header\n\t}\n\n\treturn httpReq, nil\n}\n\nfunc (svc *Service) sendHTTPRequest(httpReq *http.Request) (reqlog.ResponseLog, error) {\n\tres, err := svc.httpClient.Do(httpReq)\n\tif err != nil {\n\t\treturn reqlog.ResponseLog{}, &SendError{err}\n\t}\n\tdefer res.Body.Close()\n\n\tresLog, err := reqlog.ParseHTTPResponse(res)\n\tif err != nil {\n\t\treturn reqlog.ResponseLog{}, fmt.Errorf(\"failed to parse http response: %w\", err)\n\t}\n\n\treturn resLog, err\n}\n\nfunc (svc *Service) SetActiveProjectID(id ulid.ULID) {\n\tsvc.activeProjectID = id\n}\n\nfunc (svc *Service) DeleteRequests(ctx context.Context, projectID ulid.ULID) error {\n\treturn svc.repo.DeleteSenderRequests(ctx, projectID)\n}\n\nfunc (e SendError) Error() string {\n\treturn fmt.Sprintf(\"failed to send HTTP request: %v\", e.err)\n}\n\nfunc (e SendError) Unwrap() error {\n\treturn e.err\n}\n"
  },
  {
    "path": "pkg/sender/sender_test.go",
    "content": "package sender_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\t\"github.com/oklog/ulid\"\n\t\"go.etcd.io/bbolt\"\n\n\t\"github.com/dstotijn/hetty/pkg/db/bolt\"\n\t\"github.com/dstotijn/hetty/pkg/proj\"\n\t\"github.com/dstotijn/hetty/pkg/reqlog\"\n\t\"github.com/dstotijn/hetty/pkg/sender\"\n)\n\n//nolint:gosec\nvar ulidEntropy = rand.New(rand.NewSource(time.Now().UnixNano()))\n\nvar exampleURL = func() *url.URL {\n\tu, err := url.Parse(\"https://example.com/foobar\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn u\n}()\n\nfunc TestStoreRequest(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"without active project\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tsvc := sender.NewService(sender.Config{})\n\n\t\t_, err := svc.CreateOrUpdateRequest(context.Background(), sender.Request{\n\t\t\tURL:    exampleURL,\n\t\t\tMethod: http.MethodPost,\n\t\t\tBody:   []byte(\"foobar\"),\n\t\t})\n\t\tif !errors.Is(err, sender.ErrProjectIDMustBeSet) {\n\t\t\tt.Fatalf(\"expected `sender.ErrProjectIDMustBeSet`, got: %v\", err)\n\t\t}\n\t})\n\n\tt.Run(\"with active project\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tpath := t.TempDir() + \"bolt.db\"\n\t\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t\t}\n\t\tdefer boltDB.Close()\n\n\t\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t\t}\n\t\tdefer db.Close()\n\n\t\tsvc := sender.NewService(sender.Config{\n\t\t\tRepository: db,\n\t\t})\n\n\t\tprojectID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\t\terr = db.UpsertProject(context.Background(), proj.Project{\n\t\t\tID:       projectID,\n\t\t\tName:     \"foobar\",\n\t\t\tSettings: proj.Settings{},\n\t\t})\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error upserting project: %v\", err)\n\t\t}\n\n\t\tsvc.SetActiveProjectID(projectID)\n\t\tsvc.SetActiveProjectID(projectID)\n\n\t\texp := sender.Request{\n\t\t\tProjectID: projectID,\n\t\t\tURL:       exampleURL,\n\t\t\tMethod:    http.MethodPost,\n\t\t\tProto:     \"HTTP/1.1\",\n\t\t\tHeader: http.Header{\n\t\t\t\t\"X-Foo\": []string{\"bar\"},\n\t\t\t},\n\t\t\tBody: []byte(\"foobar\"),\n\t\t}\n\n\t\tgot, err := svc.CreateOrUpdateRequest(context.Background(), sender.Request{\n\t\t\tURL:    exampleURL,\n\t\t\tMethod: http.MethodPost,\n\t\t\tProto:  \"HTTP/1.1\",\n\t\t\tHeader: http.Header{\n\t\t\t\t\"X-Foo\": []string{\"bar\"},\n\t\t\t},\n\t\t\tBody: []byte(\"foobar\"),\n\t\t})\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error storing request: %v\", err)\n\t\t}\n\n\t\tif got.ID.Compare(ulid.ULID{}) == 0 {\n\t\t\tt.Fatal(\"expected request ID to be non-empty value\")\n\t\t}\n\n\t\tdiff := cmp.Diff(exp, got, cmpopts.IgnoreFields(sender.Request{}, \"ID\"))\n\t\tif diff != \"\" {\n\t\t\tt.Fatalf(\"request not equal (-exp, +got):\\n%v\", diff)\n\t\t}\n\n\t\tgot, err = db.FindSenderRequestByID(context.Background(), projectID, got.ID)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to find request by ID: %v\", err)\n\t\t}\n\n\t\tdiff = cmp.Diff(exp, got, cmpopts.IgnoreFields(sender.Request{}, \"ID\"))\n\t\tif diff != \"\" {\n\t\t\tt.Fatalf(\"request not equal (-exp, +got):\\n%v\", diff)\n\t\t}\n\t})\n}\n\nfunc TestCloneFromRequestLog(t *testing.T) {\n\tt.Parallel()\n\n\treqLogID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\n\tt.Run(\"without active project\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tsvc := sender.NewService(sender.Config{})\n\n\t\t_, err := svc.CloneFromRequestLog(context.Background(), reqLogID)\n\t\tif !errors.Is(err, sender.ErrProjectIDMustBeSet) {\n\t\t\tt.Fatalf(\"expected `sender.ErrProjectIDMustBeSet`, got: %v\", err)\n\t\t}\n\t})\n\n\tt.Run(\"with active project\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tpath := t.TempDir() + \"bolt.db\"\n\t\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t\t}\n\t\tdefer boltDB.Close()\n\n\t\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t\t}\n\t\tdefer db.Close()\n\n\t\tprojectID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\t\terr = db.UpsertProject(context.Background(), proj.Project{\n\t\t\tID: projectID,\n\t\t})\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error upserting project: %v\", err)\n\t\t}\n\n\t\treqLog := reqlog.RequestLog{\n\t\t\tID:        reqLogID,\n\t\t\tProjectID: projectID,\n\t\t\tURL:       exampleURL,\n\t\t\tMethod:    http.MethodPost,\n\t\t\tProto:     \"HTTP/1.1\",\n\t\t\tHeader: http.Header{\n\t\t\t\t\"X-Foo\": []string{\"bar\"},\n\t\t\t},\n\t\t\tBody: []byte(\"foobar\"),\n\t\t}\n\n\t\tif err := db.StoreRequestLog(context.Background(), reqLog); err != nil {\n\t\t\tt.Fatalf(\"failed to store request log: %v\", err)\n\t\t}\n\n\t\tsvc := sender.NewService(sender.Config{\n\t\t\tReqLogService: reqlog.NewService(reqlog.Config{\n\t\t\t\tActiveProjectID: projectID,\n\t\t\t\tRepository:      db,\n\t\t\t}),\n\t\t\tRepository: db,\n\t\t})\n\n\t\tsvc.SetActiveProjectID(projectID)\n\n\t\texp := sender.Request{\n\t\t\tSourceRequestLogID: reqLogID,\n\t\t\tProjectID:          projectID,\n\t\t\tURL:                exampleURL,\n\t\t\tMethod:             http.MethodPost,\n\t\t\tProto:              sender.HTTPProto20,\n\t\t\tHeader: http.Header{\n\t\t\t\t\"X-Foo\": []string{\"bar\"},\n\t\t\t},\n\t\t\tBody: []byte(\"foobar\"),\n\t\t}\n\n\t\tgot, err := svc.CloneFromRequestLog(context.Background(), reqLogID)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error cloning from request log: %v\", err)\n\t\t}\n\n\t\tdiff := cmp.Diff(exp, got, cmpopts.IgnoreFields(sender.Request{}, \"ID\"))\n\t\tif diff != \"\" {\n\t\t\tt.Fatalf(\"request not equal (-exp, +got):\\n%v\", diff)\n\t\t}\n\t})\n}\n\nfunc TestSendRequest(t *testing.T) {\n\tt.Parallel()\n\n\tpath := t.TempDir() + \"bolt.db\"\n\tboltDB, err := bbolt.Open(path, 0o600, nil)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to open bolt database: %v\", err)\n\t}\n\tdefer boltDB.Close()\n\n\tdb, err := bolt.DatabaseFromBoltDB(boltDB)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create database: %v\", err)\n\t}\n\tdefer db.Close()\n\n\tdate := time.Now().Format(http.TimeFormat)\n\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Foobar\", \"baz\")\n\t\tw.Header().Set(\"Date\", date)\n\t\tfmt.Fprint(w, \"baz\")\n\t}))\n\tdefer ts.Close()\n\n\ttsURL, _ := url.Parse(ts.URL)\n\n\tprojectID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\terr = db.UpsertProject(context.Background(), proj.Project{\n\t\tID:       projectID,\n\t\tSettings: proj.Settings{},\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error upserting project: %v\", err)\n\t}\n\n\treqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)\n\treq := sender.Request{\n\t\tID:        reqID,\n\t\tProjectID: projectID,\n\t\tURL:       tsURL,\n\t\tMethod:    http.MethodPost,\n\t\tProto:     \"HTTP/1.1\",\n\t\tHeader: http.Header{\n\t\t\t\"X-Foo\": []string{\"bar\"},\n\t\t},\n\t\tBody: []byte(\"foobar\"),\n\t}\n\n\tif err := db.StoreSenderRequest(context.Background(), req); err != nil {\n\t\tt.Fatalf(\"failed to store request: %v\", err)\n\t}\n\n\tsvc := sender.NewService(sender.Config{\n\t\tReqLogService: reqlog.NewService(reqlog.Config{\n\t\t\tRepository: db,\n\t\t}),\n\t\tRepository: db,\n\t})\n\tsvc.SetActiveProjectID(projectID)\n\n\texp := &reqlog.ResponseLog{\n\t\tProto:      \"HTTP/1.1\",\n\t\tStatusCode: http.StatusOK,\n\t\tStatus:     \"200 OK\",\n\t\tHeader: http.Header{\n\t\t\t\"Content-Length\": []string{\"3\"},\n\t\t\t\"Content-Type\":   []string{\"text/plain; charset=utf-8\"},\n\t\t\t\"Date\":           []string{date},\n\t\t\t\"Foobar\":         []string{\"baz\"},\n\t\t},\n\t\tBody: []byte(\"baz\"),\n\t}\n\n\tgot, err := svc.SendRequest(context.Background(), reqID)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error sending request: %v\", err)\n\t}\n\n\tdiff := cmp.Diff(exp, got.Response, cmpopts.IgnoreFields(sender.Request{}, \"ID\"))\n\tif diff != \"\" {\n\t\tt.Fatalf(\"request not equal (-exp, +got):\\n%v\", diff)\n\t}\n}\n"
  },
  {
    "path": "pkg/sender/transport.go",
    "content": "package sender\n\nimport (\n\t\"crypto/tls\"\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n)\n\ntype HTTPTransport struct{}\n\ntype protoCtxKey struct{}\n\nconst (\n\tHTTPProto10 = \"HTTP/1.0\"\n\tHTTPProto11 = \"HTTP/1.1\"\n\tHTTPProto20 = \"HTTP/2.0\"\n)\n\n// h1OnlyTransport mimics `http.DefaultTransport`, but with HTTP/2 disabled.\nvar h1OnlyTransport = &http.Transport{\n\tProxy: http.ProxyFromEnvironment,\n\tDialContext: (&net.Dialer{\n\t\tTimeout:   30 * time.Second,\n\t\tKeepAlive: 30 * time.Second,\n\t}).DialContext,\n\tMaxIdleConns:          100,\n\tIdleConnTimeout:       90 * time.Second,\n\tTLSHandshakeTimeout:   10 * time.Second,\n\tExpectContinueTimeout: 1 * time.Second,\n\n\t// Disable HTTP/2.\n\tTLSNextProto: map[string]func(string, *tls.Conn) http.RoundTripper{},\n}\n\n// RountTrip implements http.RoundTripper. Based on a context value on the\n// HTTP request, it switches between using `http.DefaultTransport` (which attempts\n// HTTP/2) and a HTTP/1.1 only transport that's based off `http.DefaultTransport`.\nfunc (t *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {\n\tproto, ok := req.Context().Value(protoCtxKey{}).(string)\n\n\tif ok && proto == HTTPProto10 || proto == HTTPProto11 {\n\t\treturn h1OnlyTransport.RoundTrip(req)\n\t}\n\n\treturn http.DefaultTransport.RoundTrip(req)\n}\n\nfunc isValidProto(proto string) bool {\n\treturn proto == HTTPProto10 || proto == HTTPProto11 || proto == HTTPProto20\n}\n"
  },
  {
    "path": "tools.go",
    "content": "//go:build tools\n// +build tools\n\npackage tools\n\nimport (\n\t_ \"github.com/99designs/gqlgen\"\n)\n"
  }
]