├── .adr-dir ├── .air.toml ├── .cursorrules ├── .dockerignore ├── .editorconfig ├── .env ├── .gitattributes ├── .github ├── ARCHITECTURE.md ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── 01_bug_report.yml │ ├── 02_feature_request.yml │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md ├── SECURITY.md ├── codecov.yml ├── copilot-instructions.md ├── dependabot.yml ├── typos.toml └── workflows │ ├── deployment.yml │ └── integrity.yml ├── .gitignore ├── .golangci.yaml ├── .pre-commit-config.yaml ├── .tool-versions ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── LICENSE ├── Makefile ├── README.md ├── bin └── sqlc-gen-go.wasm ├── cmd ├── manage │ ├── main.go │ └── subcommands │ │ └── healthcheck.go ├── migrate │ └── main.go └── serve │ └── main.go ├── config.json ├── etc └── data │ └── default │ ├── migrations │ └── 0001_create_channels.sql │ └── queries │ └── channels.sql ├── go.mod ├── go.sum ├── ops ├── deployment │ └── fly.toml ├── docker │ ├── Dockerfile │ ├── compose.production.yml │ ├── compose.yml │ └── resources │ │ ├── fluentd │ │ ├── Dockerfile │ │ └── fluentd.conf │ │ ├── grafana │ │ ├── dashboards │ │ │ └── main.json │ │ └── provisioning │ │ │ ├── dashboards │ │ │ └── dashboards.yaml │ │ │ └── datasources │ │ │ ├── loki.yaml │ │ │ └── prometheus.yaml │ │ ├── loki │ │ └── local_config.yaml │ │ └── prometheus │ │ └── prometheus.yml └── load_tests │ ├── definitions │ └── broadcast.proto │ ├── go_grpc.js │ └── go_http.js ├── pkg └── sample │ ├── adapters │ ├── appcontext │ │ ├── appcontext.go │ │ └── config.go │ ├── grpc │ │ ├── generated │ │ │ ├── broadcast.pb.go │ │ │ └── broadcast_grpc.pb.go │ │ └── grpc.go │ ├── http │ │ └── http.go │ └── storage │ │ ├── channels.sql.go │ │ ├── db.go │ │ └── db_gen.go │ └── business │ ├── channels │ ├── service.go │ └── types_gen.go │ └── tenants │ ├── service.go │ └── types.go ├── sqlc.yaml └── tmp └── .gitkeep /.adr-dir: -------------------------------------------------------------------------------- 1 | docs/adr 2 | -------------------------------------------------------------------------------- /.air.toml: -------------------------------------------------------------------------------- 1 | root = "." 2 | testdata_dir = "testdata" 3 | tmp_dir = "tmp" 4 | 5 | [build] 6 | args_bin = [] 7 | bin = "./tmp/service-cli" 8 | cmd = "go build -o ./tmp/service-cli ./cmd/service-cli/" 9 | delay = 1000 10 | exclude_dir = ["tmp", "vendor", "testdata"] 11 | exclude_file = [] 12 | exclude_regex = ["_test.go"] 13 | exclude_unchanged = false 14 | follow_symlink = false 15 | full_bin = "" 16 | include_dir = ["cmd", "pkg"] 17 | include_ext = ["go", "tpl", "tmpl", "html"] 18 | include_file = [] 19 | kill_delay = "0s" 20 | log = "build-errors.log" 21 | poll = false 22 | poll_interval = 0 23 | post_cmd = [] 24 | pre_cmd = [] 25 | rerun = false 26 | rerun_delay = 500 27 | send_interrupt = false 28 | stop_on_error = true 29 | 30 | [color] 31 | app = "" 32 | build = "yellow" 33 | main = "magenta" 34 | runner = "green" 35 | watcher = "cyan" 36 | 37 | [log] 38 | main_only = false 39 | time = false 40 | 41 | [misc] 42 | clean_on_exit = false 43 | 44 | [proxy] 45 | app_port = 0 46 | enabled = false 47 | proxy_port = 0 48 | 49 | [screen] 50 | clear_on_rebuild = false 51 | keep_scroll = true 52 | -------------------------------------------------------------------------------- /.cursorrules: -------------------------------------------------------------------------------- 1 | ./.github/copilot-instructions.md -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .github/* 2 | .vscode/* 3 | tmp/* 4 | .dockerignore 5 | .editorconfig 6 | .gitattributes 7 | .gitignore 8 | .pre-commit-config.yaml 9 | .tool-versions 10 | LICENSE 11 | README.md 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | # editorconfig-tools is unable to ignore longs strings or urls 14 | max_line_length = off 15 | 16 | [{*.md,*.mdx,*.mdoc}] 17 | trim_trailing_whitespace = false 18 | 19 | [{Makefile,go.mod,go.sum,*.go,.gitmodules}] 20 | indent_style = tab 21 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # APP_NAME=go-service 2 | # APP_ENV=production 3 | PORT=8080 4 | 5 | # LOG__TARGET=stdout 6 | # LOG__LEVEL=info 7 | 8 | # HTTP__CORS_ORIGIN= 9 | # HTTP__CORS_STRICT_HEADERS= 10 | 11 | # JWT_SIGNATURE= 12 | 13 | # METRICS__PROMETHEUS_ADDR=localhost:9090 14 | # DATA__CONNSTR= 15 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior as unix line endings for all text files, 2 | # in case people don't have core.autocrlf set. 3 | * text=auto eol=lf 4 | -------------------------------------------------------------------------------- /.github/ARCHITECTURE.md: -------------------------------------------------------------------------------- 1 | # Architecture Guide 2 | 3 | This guide explains how this full-stack codebase is organized. 4 | 5 | ## File Structure 6 | 7 | | Folder | Description | 8 | | --------------- | --------------------------- | 9 | | `cmd/` | Command-line applications | 10 | | `ops/` | Operations | 11 | | `pkg/` | Packages | 12 | | `tmp/` | Temporary files | 13 | 14 | - All command-line applications and packages are placed in the `cmd` and `pkg` folders, respectively. 15 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @eser 2 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | See [@eser/directives](https://github.com/eser/stack/blob/dev/pkg/%40eser/directives/README.md) for our sets of rules 4 | and recommendations we follow. 5 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 👍🎉 First off, thanks for taking the time to contribute! 🎉👍 4 | 5 | The following is a set of guidelines for contributing to this project and its components, which are hosted in GitHub. 6 | These are mostly guidelines, not strict rules. Use your best judgment and feel free to propose changes to this document 7 | in a pull request. 8 | 9 | ## What Should I Know Before I Get Started? 10 | 11 | ### Code of Conduct 12 | 13 | This project and everyone participating in it is governed by the 14 | [@eser/directives](https://github.com/eser/stack/blob/dev/pkg/%40eser/directives/README.md). By participating, you are 15 | expected to uphold this code. Please report unacceptable behavior as in specified in the link. 16 | 17 | ### Technical Requirements 18 | 19 | Just familiarity with JavaScript and Git. 20 | 21 | ### Conventions 22 | 23 | Using existing precommit hooks should be fine for now. Please ensure your submissions are formatted accordingly. 24 | 25 | ### Design Decisions 26 | 27 | Before making significant changes, please open a new issue to discuss the proposed changes and its design first. 28 | 29 | ### Get in Touch 30 | 31 | You can reach out to us in our [Discord channel](https://discord.com/channels/1139067412105396304/1283540458739335189) 32 | for any questions, suggestions, or feedback. 33 | 34 | ## How Can I Contribute? 35 | 36 | It is publicly open for any contribution. Here are some ideas you can begin from: 37 | 38 | - Reporting bugs 39 | - Suggesting enhancements and new features 40 | - Implementing performance improvements 41 | - Improving documentation 42 | - Submitting bug fixes 43 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [eser] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/01_bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report. 3 | title: "[Bug Report]: " 4 | labels: ["bug", "triage"] 5 | projects: ["eser/golang-service-template"] 6 | assignees: 7 | - eser 8 | body: 9 | - type: markdown 10 | attributes: 11 | value: | 12 | Thanks for taking the time to fill out this bug report! 13 | - type: input 14 | id: contact 15 | attributes: 16 | label: Contact Details 17 | description: How can we get in touch with you if we need more info? 18 | placeholder: ex. x.com/eser 19 | validations: 20 | required: false 21 | - type: textarea 22 | id: problem-statement 23 | attributes: 24 | label: What happened? 25 | description: Describe the problem, what did you expect to happen? How can we reproduce this? 26 | placeholder: Tell us what have you encountered. 27 | validations: 28 | required: true 29 | - type: dropdown 30 | id: browsers 31 | attributes: 32 | label: What platforms are you seeing the problem on? 33 | multiple: true 34 | options: 35 | - Chromium-based (Chrome, Edge, Arc, etc.) 36 | - Firefox 37 | - Safari 38 | - iOS 39 | - Android 40 | - CLI 41 | - type: textarea 42 | id: logs 43 | attributes: 44 | label: Relevant log output 45 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 46 | render: shell 47 | - type: checkboxes 48 | id: terms 49 | attributes: 50 | label: Code of Conduct 51 | description: By submitting this form, you agree to follow our **Code of Conduct**. 52 | options: 53 | - label: I agree to follow this project's Code of Conduct 54 | required: true 55 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/02_feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest an idea or voice a concern. 3 | title: "[Feature Request]: " 4 | labels: ["enhancement", "triage"] 5 | projects: ["eser/golang-service-template"] 6 | assignees: 7 | - eser 8 | body: 9 | - type: markdown 10 | attributes: 11 | value: | 12 | Thanks for taking the time to fill out this feature request! 13 | - type: input 14 | id: contact 15 | attributes: 16 | label: Contact Details 17 | description: How can we get in touch with you if we need more info? 18 | placeholder: ex. x.com/eser 19 | validations: 20 | required: false 21 | - type: textarea 22 | id: problem-statement 23 | attributes: 24 | label: Is your feature request related to a problem? 25 | description: A clear and concise description of what the problem statement is. 26 | placeholder: Ex. I'm frustrated when [...] 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: expectation 31 | attributes: 32 | label: Describe the expectated behavior you'd like 33 | description: A clear and concise description of what you want to happen. 34 | validations: 35 | required: true 36 | - type: textarea 37 | id: additional-context 38 | attributes: 39 | label: Additional context 40 | description: Add any other context or screenshots about the feature request here. 41 | validations: 42 | required: false 43 | - type: checkboxes 44 | id: terms 45 | attributes: 46 | label: Code of Conduct 47 | description: By submitting this form, you agree to follow our **Code of Conduct**. 48 | options: 49 | - label: I agree to follow this project's Code of Conduct 50 | required: true 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: eser.live Discord 4 | url: https://discord.eser.live/ 5 | about: Please connect with us here. 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Fixes issue 2 | 3 | 4 | 5 | Fixes # 6 | 7 | ## Changes proposed 8 | 9 | 10 | 11 | ## Check List (Check all the applicable boxes) 12 | 13 | - [x] The title of my pull request is a short description of the requested changes. 14 | - [x] My code follows the code style of this project. 15 | - [ ] My change requires changes to the documentation. 16 | - [ ] I have updated the documentation accordingly. 17 | - [x] This PR does not contain plagiarized content. 18 | - [x] My submissions follows the **Submission Rules** 19 | - [x] I have read and accepted the **Terms and Conditions** 20 | 21 | ## Screenshots 22 | 23 | 24 | 25 | ## Note to reviewers 26 | 27 | 28 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Currently, only the latest on `main` branch is supported with security updates. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | To report a vulnerability, open a new issue in the [issue tracker](https://github.com/eser/golang-service-template/issues). 10 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | informational: true 8 | 9 | patch: 10 | default: 11 | informational: true 12 | 13 | # ignore: 14 | # - "**/*.tsx" 15 | -------------------------------------------------------------------------------- /.github/copilot-instructions.md: -------------------------------------------------------------------------------- 1 | When working with this codebase, please follow these architectural principles and guidelines: 2 | 3 | 1. Hexagonal Architecture 4 | - The codebase follows strict hexagonal architecture (ports and adapters) principles 5 | - Business logic in pkg/sample/business/ must not have external dependencies 6 | - All external interactions must go through interfaces (ports) defined in the business layer 7 | - Adapters in pkg/sample/adapters/ implement these interfaces 8 | - Ports exist as interfaces in the business layer 9 | 10 | 1. Dependency Rules 11 | - Business logic can only depend on other business logic 12 | - Adapters can only depend on business interfaces they implement 13 | - No circular dependencies allowed 14 | - Entry points (cmd/) wire everything together using dependency injection 15 | 16 | 1. Package Structure 17 | - Business logic packages should define their interfaces and types first 18 | - Each business domain should have its own package under pkg/sample/business/ 19 | - Adapters should be organized by technology (http, storage, etc.) 20 | - Configuration should be injected via the appcontext 21 | 22 | 1. Conventions 23 | - Use snake_case for file names. 24 | - Follow idiomatic Go conventions. 25 | 26 | 1. Code Generation 27 | - Database code is generated using sqlc 28 | - Maintain clean separation between generated and hand-written code 29 | 30 | 1. Error Handling 31 | - Business errors should be defined in the business layer 32 | - Wrap external errors before returning them 33 | - Use meaningful error types and messages 34 | - Avoid panic as much as possible (especially in business logic) 35 | 36 | 1. Testing 37 | - Business logic must have unit tests 38 | - Adapters should have integration tests 39 | - Use interfaces for mocking in tests 40 | - Test files should be next to their tested code with package names prefixed with _test 41 | 42 | 1. Configuration 43 | - Use environment variables for runtime configuration 44 | - Keep secrets out of the codebase 45 | - Use .env.local and config.local.json for development overrides 46 | 47 | 1. Database 48 | - All SQL queries should be in etc/data/{datasource_name}/queries/ 49 | - Use migrations for schema changes 50 | - Keep migrations forward-only 51 | - Document schema changes 52 | 53 | Remember: 54 | - Business logic is sacred - keep it clean and dependency-free 55 | - All external interactions must go through well-defined interfaces 56 | - Maintain clear separation between layers 57 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: "docker" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | commit-message: 9 | prefix: "deps(docker): " 10 | include: "scope" 11 | labels: 12 | - "dependencies" 13 | 14 | - package-ecosystem: "github-actions" 15 | directory: "/" 16 | schedule: 17 | interval: "weekly" 18 | commit-message: 19 | prefix: "deps(gh-actions): " 20 | include: "scope" 21 | labels: 22 | - "dependencies" 23 | 24 | - package-ecosystem: "gomod" 25 | directory: "/" 26 | schedule: 27 | interval: "weekly" 28 | commit-message: 29 | prefix: "deps(gomod): " 30 | include: "scope" 31 | labels: 32 | - "dependencies" 33 | -------------------------------------------------------------------------------- /.github/typos.toml: -------------------------------------------------------------------------------- 1 | [default.extend-words] 2 | Encrypter = "Encrypter" 3 | -------------------------------------------------------------------------------- /.github/workflows/deployment.yml: -------------------------------------------------------------------------------- 1 | name: Deployment Pipeline 2 | 3 | on: 4 | push: 5 | tags: 6 | - v[0-9]+.[0-9]+.[0-9]+* 7 | 8 | concurrency: 9 | group: ${{ github.ref }}-deployment 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | deployment: 14 | name: Deployment 15 | runs-on: ubuntu-latest 16 | 17 | permissions: 18 | contents: read 19 | 20 | strategy: 21 | fail-fast: false 22 | 23 | steps: 24 | - name: Checkout repository 25 | uses: actions/checkout@v4 26 | with: 27 | fetch-depth: 2 28 | 29 | - name: Determine Variables 30 | run: | 31 | TAG="${GITHUB_REF#refs/tags/}" 32 | 33 | if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then 34 | DEPLOY_ENV=production 35 | elif [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc(\.[0-9]+)?$ ]]; then 36 | DEPLOY_ENV=stage 37 | elif [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-dev(\.[0-9]+)?$ ]]; then 38 | DEPLOY_ENV=test 39 | else 40 | echo "Error: Unrecognized tag format: $TAG" 41 | exit 1 42 | fi 43 | 44 | IMAGE_TAG=${GITHUB_REF#refs/tags/} 45 | if [ -z "$IMAGE_TAG" ]; then 46 | IMAGE_TAG=$(git rev-parse --short HEAD) 47 | fi 48 | 49 | IMAGE_NAME=gcr.io/${{ secrets.GCLOUD_PROJECT }}/${{ secrets.APP_NAME }}:$IMAGE_TAG 50 | 51 | echo "TAG=$TAG" >> $GITHUB_ENV 52 | echo "DEPLOY_ENV=$DEPLOY_ENV" >> $GITHUB_ENV 53 | echo "IMAGE_NAME=$IMAGE_NAME" >> $GITHUB_ENV 54 | echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV 55 | 56 | - name: Show Results 57 | run: | 58 | echo "TAG=$TAG" 59 | echo "DEPLOY_ENV=$DEPLOY_ENV" 60 | echo "IMAGE_NAME=$IMAGE_NAME" 61 | echo "IMAGE_TAG=$IMAGE_TAG" 62 | -------------------------------------------------------------------------------- /.github/workflows/integrity.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a golang project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go 3 | 4 | name: Integrity Pipeline 5 | 6 | on: 7 | push: 8 | branches: 9 | - "**" 10 | tags: 11 | - v[0-9]+.[0-9]+.[0-9]+* 12 | 13 | pull_request: 14 | types: 15 | - opened 16 | - edited # in case of base branch change 17 | - synchronize 18 | # - reopened 19 | # - ready_for_review 20 | branches: 21 | - "**" 22 | 23 | # schedule: 24 | # - cron: "18 21 * * 6" 25 | 26 | # Allows you to run this workflow manually from the Actions tab on GitHub. 27 | workflow_dispatch: 28 | inputs: 29 | create_release: 30 | description: Create a release 31 | required: false 32 | type: boolean 33 | 34 | concurrency: 35 | group: ${{ github.ref }}-integrity 36 | cancel-in-progress: true 37 | 38 | jobs: 39 | integration: 40 | name: Integration 41 | runs-on: ${{ matrix.os }} 42 | 43 | permissions: 44 | contents: read # Needed to clone the repository 45 | 46 | strategy: 47 | fail-fast: false 48 | matrix: 49 | os: 50 | - ubuntu-latest 51 | # - windows-latest 52 | # - macOS-latest 53 | golang-version: 54 | - 1.24.2 55 | 56 | steps: 57 | - name: Checkout repository 58 | uses: actions/checkout@v4 59 | with: 60 | fetch-depth: 2 61 | 62 | - name: Setup Python 63 | uses: actions/setup-python@v5 64 | with: 65 | python-version: "3.x" 66 | 67 | - name: Setup Golang ${{ matrix.golang-version }} 68 | uses: actions/setup-go@v5 69 | with: 70 | go-version: ${{ matrix.golang-version }} 71 | cache: true 72 | cache-dependency-path: go.sum 73 | 74 | - name: Setup checkers 75 | run: make init-checkers 76 | 77 | - name: Run pre-commit 78 | uses: pre-commit/action@v3.0.1 79 | 80 | - name: Build 81 | working-directory: ./ 82 | run: go build -v ./... 83 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # OS-specific files 4 | .DS_Store 5 | Thumbs.db 6 | 7 | # Editor metadata 8 | .vscode/* 9 | !.vscode/extensions.json 10 | !.vscode/launch.json 11 | !.vscode/settings.json 12 | .idea/* 13 | 14 | # local API keys and secrets 15 | .env.local 16 | .env.*.local 17 | config.local.json 18 | config.*.local.json 19 | 20 | # sensitive files 21 | *.key 22 | *.pem 23 | *.swp 24 | 25 | # Binaries for programs and plugins 26 | *.exe 27 | *.exe~ 28 | *.dll 29 | *.so 30 | *.dylib 31 | 32 | # Test binaries, coverage and testing tool outputs 33 | *.test 34 | *.out 35 | cov_profile.lcov 36 | 37 | # Dependency directories (remove the comment below to include it) 38 | # vendor/ 39 | 40 | # Build output and temporary files 41 | __debug_bin* 42 | build-errors.log 43 | tmp/* 44 | !tmp/.gitkeep 45 | 46 | # Todos 47 | TODOS 48 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 3m 3 | issues-exit-code: 1 4 | tests: true 5 | allow-parallel-runners: true 6 | concurrency: 4 7 | 8 | output: 9 | formats: 10 | - format: colored-line-number 11 | sort-results: true 12 | 13 | linters: 14 | enable-all: true 15 | disable: 16 | - godox 17 | - stylecheck 18 | - exportloopref 19 | 20 | linters-settings: 21 | depguard: 22 | rules: 23 | main: 24 | deny: 25 | - pkg: io/ioutil 26 | desc: The io/ioutil package has been deprecated, see https://go.dev/doc/go1.16#ioutil 27 | allow: 28 | - $gostd 29 | - golang.org/x/net/http/httpguts 30 | - google.golang.org/grpc 31 | - google.golang.org/grpc/reflection 32 | - google.golang.org/grpc/status 33 | - github.com/eser/ajan 34 | - github.com/eser/go-service 35 | - github.com/oklog/ulid/v2 36 | - github.com/go-playground/validator/v10 37 | - github.com/stretchr/testify 38 | - github.com/go-faker/faker/v4 39 | - github.com/getkin/kin-openapi/openapi3 40 | - github.com/golang-jwt/jwt/v5 41 | - github.com/prometheus/client_golang/prometheus 42 | - github.com/pressly/goose/v3 43 | - github.com/lib/pq 44 | - github.com/spf13/cobra 45 | revive: 46 | # enable-all-rules: true 47 | ignore-generated-header: true 48 | severity: warning 49 | rules: 50 | - name: var-naming 51 | disabled: true 52 | arguments: [] 53 | # - name: exported 54 | # severity: warning 55 | # - name: error-return 56 | # severity: warning 57 | # - name: error-naming 58 | # severity: warning 59 | # - name: if-return 60 | # severity: warning 61 | # - name: var-naming 62 | # severity: warning 63 | # - name: var-declaration 64 | # severity: warning 65 | # - name: receiver-naming 66 | # severity: warning 67 | # - name: errorf 68 | # severity: warning 69 | # - name: empty-block 70 | # severity: warning 71 | # - name: unused-parameter 72 | # severity: warning 73 | # - name: unreachable-code 74 | # severity: warning 75 | # - name: redefines-builtin-id 76 | # severity: warning 77 | # - name: superfluous-else 78 | # severity: warning 79 | # - name: unexported-return 80 | # severity: warning 81 | # - name: indent-error-flow 82 | # severity: warning 83 | # - name: blank-imports 84 | # severity: warning 85 | # - name: range 86 | # severity: warning 87 | # - name: time-naming 88 | # severity: warning 89 | # - name: context-as-argument 90 | # severity: warning 91 | # - name: context-keys-type 92 | # severity: warning 93 | # - name: indent-error-flow 94 | # severity: warning 95 | 96 | issues: 97 | fix: true 98 | exclude-use-default: false 99 | exclude-dirs: 100 | - ops 101 | - tmp 102 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v5.0.0 4 | hooks: 5 | - id: check-added-large-files 6 | args: ["--maxkb=1024"] 7 | exclude: | 8 | (?x)^( 9 | bin/sqlc-gen-go.wasm 10 | )$ 11 | - id: check-case-conflict 12 | - id: check-executables-have-shebangs 13 | - id: check-json 14 | - id: check-merge-conflict 15 | - id: check-shebang-scripts-are-executable 16 | - id: check-symlinks 17 | - id: check-toml 18 | - id: check-xml 19 | - id: check-yaml 20 | args: [--allow-multiple-documents] 21 | - id: destroyed-symlinks 22 | - id: detect-private-key 23 | - id: end-of-file-fixer 24 | - id: fix-byte-order-marker 25 | - id: forbid-new-submodules 26 | - id: mixed-line-ending 27 | args: ["--fix=lf"] 28 | - id: pretty-format-json 29 | args: ["--autofix", "--no-ensure-ascii", "--no-sort-keys"] 30 | - id: trailing-whitespace 31 | - repo: https://github.com/crate-ci/typos 32 | rev: v1.29.5 33 | hooks: 34 | - id: typos 35 | verbose: true 36 | args: 37 | - "--config" 38 | - ".github/typos.toml" 39 | exclude: | 40 | (?x)^( 41 | go.mod 42 | )$ 43 | - repo: https://github.com/compilerla/conventional-pre-commit 44 | rev: v4.0.0 45 | hooks: 46 | - id: conventional-pre-commit 47 | stages: [commit-msg] 48 | args: [] 49 | - repo: https://github.com/golangci/golangci-lint 50 | rev: v1.63.4 51 | hooks: 52 | - id: golangci-lint 53 | - repo: local 54 | hooks: 55 | - id: checks 56 | name: checks 57 | entry: make check 58 | language: golang 59 | pass_filenames: false 60 | types: 61 | - go 62 | - id: snake-case-files-only 63 | name: snake_case files only 64 | entry: filenames must be snake_case only 65 | language: fail 66 | files: '[^a-z0-9_\.\/\[\]@]' 67 | exclude: | 68 | (?x)^( 69 | .github/.*| 70 | bin/sqlc-gen-go.wasm| 71 | ops/docker/resources/fluentd/Dockerfile| 72 | ops/docker/Dockerfile| 73 | .adr-dir| 74 | .pre-commit-config.yaml| 75 | .tool-versions| 76 | LICENSE| 77 | Makefile| 78 | README.md 79 | )$ 80 | - id: run-tests 81 | name: run tests 82 | description: Run tests using Go's built-in test runner. 83 | entry: make test-ci 84 | types_or: [go, json] 85 | pass_filenames: false 86 | language: system 87 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | pre-commit 3.8.0 2 | golang 1.24.2 3 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "chdsbd.github-code-owners", 4 | "EditorConfig.EditorConfig", 5 | "github.vscode-github-actions", 6 | "golang.go", 7 | "ms-vscode.makefile-tools", 8 | "ryanluker.vscode-coverage-gutters" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Launch serve", 6 | "type": "go", 7 | "request": "launch", 8 | "mode": "auto", 9 | "cwd": "${workspaceFolder}", 10 | "program": "cmd/serve/" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "coverage-gutters.coverageBaseDir": "./", 3 | "coverage-gutters.coverageFileNames": [ 4 | "cov_profile.lcov" 5 | ], 6 | "coverage-gutters.showGutterCoverage": true, 7 | "coverage-gutters.showLineCoverage": true, 8 | "coverage-gutters.showRulerCoverage": true, 9 | "go.testFlags": [ 10 | "-failfast" 11 | ], 12 | "go.toolsManagement.autoUpdate": true, 13 | "go.useLanguageServer": true, 14 | "go.vetOnSave": "package", 15 | "go.lintFlags": [ 16 | "--build-tags=integration,unit" 17 | ], 18 | "go.lintOnSave": "package", 19 | "go.lintTool": "golangci-lint", 20 | "go.inlayHints.parameterNames": true, 21 | "go.inlayHints.rangeVariableTypes": true, 22 | "go.inlayHints.constantValues": true, 23 | "go.inlayHints.functionTypeParameters": true, 24 | "go.inlayHints.compositeLiteralTypes": true, 25 | "go.inlayHints.compositeLiteralFields": true, 26 | "go.inlayHints.assignVariableTypes": true, 27 | "gopls": { 28 | "build.buildFlags": [ 29 | "-tags=integration,unit" 30 | ], 31 | "ui.semanticTokens": true 32 | }, 33 | "makefile.configureOnOpen": false, 34 | "files.associations": { 35 | "*.mdoc": "markdown", 36 | "*.mdx": "markdown" 37 | }, 38 | "files.exclude": { 39 | "**/tmp": true, 40 | ".vscode/extensions.json": false, 41 | ".adr-dir": false, 42 | ".air.toml": false, 43 | ".editorconfig": false, 44 | ".gitattributes": false, 45 | "go.sum": false, 46 | "LICENSE": false 47 | }, 48 | "redhat.telemetry.enabled": false, 49 | "yaml.schemas": { 50 | "https://json.schemastore.org/github-workflow.json": "./.github/workflows/*.yml" 51 | }, 52 | "[codeowners]": { 53 | "editor.defaultFormatter": "chdsbd.github-code-owners" 54 | }, 55 | "[go]": { 56 | "editor.defaultFormatter": "golang.go" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2024-present Eser Ozvataf and other contributors. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # .RECIPEPREFIX := $(.RECIPEPREFIX) 2 | TESTCOVERAGE_THRESHOLD=0 3 | 4 | ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)) 5 | 6 | default: help 7 | 8 | .PHONY: help 9 | help: ## Shows help for each of the Makefile recipes. 10 | @echo 'Commands:' 11 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' 12 | 13 | .PHONY: dep 14 | dep: ## Downloads dependencies. 15 | go mod download 16 | go mod tidy 17 | 18 | .PHONY: init-tools 19 | init-tools: ## Initializes tools. 20 | command -v pre-commit >/dev/null || brew install pre-commit 21 | [ -f .git/hooks/pre-commit ] || pre-commit install 22 | command -v make >/dev/null || brew install make 23 | command -v act >/dev/null || brew install act 24 | command -v protoc >/dev/null || brew install protobuf 25 | go tool -n air >/dev/null || go get -tool github.com/air-verse/air@latest 26 | 27 | .PHONY: init-generators 28 | init-generators: ## Initializes generators. 29 | go tool -n sqlc >/dev/null || go get -tool github.com/sqlc-dev/sqlc/cmd/sqlc@latest 30 | go tool -n mockery > /dev/null || go get -tool github.com/vektra/mockery/v2@latest 31 | go tool -n stringer >/dev/null || go get -tool golang.org/x/tools/cmd/stringer@latest 32 | go tool -n gcov2lcov >/dev/null || go get -tool github.com/jandelgado/gcov2lcov@latest 33 | go tool -n protoc-gen-go >/dev/null || go get -tool google.golang.org/protobuf/cmd/protoc-gen-go@latest 34 | go tool -n protoc-gen-go-grpc >/dev/null || go get -tool google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 35 | 36 | .PHONY: init-checkers 37 | init-checkers: ## Initializes checkers. 38 | go tool -n golangci-lint >/dev/null || go get -tool github.com/golangci/golangci-lint/cmd/golangci-lint@latest 39 | go tool -n betteralign >/dev/null || go get -tool github.com/dkorunic/betteralign/cmd/betteralign@latest 40 | go tool -n govulncheck >/dev/null || go get -tool golang.org/x/vuln/cmd/govulncheck@latest 41 | 42 | .PHONY: init 43 | init: init-tools init-generators init-checkers dep # Initializes the project. 44 | # cp -n .env.example .env || true 45 | 46 | .PHONY: generate 47 | generate: ## Runs auto-generated code generation tools. 48 | go generate ./... 49 | 50 | .PHONY: migrate 51 | migrate: ## Runs the migration command. 52 | go run ./cmd/migrate/ $(ARGS) 53 | 54 | .PHONY: build 55 | build: ## Builds the entire codebase. 56 | go build -v ./... 57 | 58 | .PHONY: clean 59 | clean: ## Cleans the entire codebase. 60 | go clean 61 | 62 | .PHONY: dev 63 | dev: ## Runs the service in development mode. 64 | go tool air --build.bin "./tmp/serve" --build.cmd "go build -o ./tmp/serve ./cmd/serve/" 65 | 66 | .PHONY: run 67 | run: ## Runs the service. 68 | go run ./cmd/serve/ 69 | 70 | .PHONY: test 71 | test: ## Runs the tests. 72 | go test -failfast -race -count 1 ./... 73 | 74 | .PHONY: test-cov 75 | test-cov: ## Runs the tests with coverage. 76 | go test -failfast -race -count 1 -coverpkg=./... -coverprofile=${TMPDIR}cov_profile.out ./... 77 | # go tool gcov2lcov -infile ${TMPDIR}cov_profile.out -outfile ./cov_profile.lcov 78 | 79 | .PHONY: test-view-html 80 | test-view-html: ## Views the test coverage in HTML. 81 | go tool cover -html ${TMPDIR}cov_profile.out -o ${TMPDIR}cov_profile.html 82 | open ${TMPDIR}cov_profile.html 83 | 84 | .PHONY: test-ci 85 | test-ci: test-cov # Runs the tests with coverage and check if it's above the threshold. 86 | $(eval ACTUAL_COVERAGE := $(shell go tool cover -func=${TMPDIR}cov_profile.out | grep total | grep -Eo '[0-9]+\.[0-9]+')) 87 | 88 | @echo "Quality Gate: checking test coverage is above threshold..." 89 | @echo "Threshold : $(TESTCOVERAGE_THRESHOLD) %" 90 | @echo "Current test coverage : $(ACTUAL_COVERAGE) %" 91 | 92 | @if [ "$(shell echo "$(ACTUAL_COVERAGE) < $(TESTCOVERAGE_THRESHOLD)" | bc -l)" -eq 1 ]; then \ 93 | echo "Current test coverage is below threshold. Please add more unit tests or adjust threshold to a lower value."; \ 94 | echo "Failed"; \ 95 | exit 1; \ 96 | else \ 97 | echo "OK"; \ 98 | fi 99 | 100 | .PHONY: lint 101 | lint: ## Runs the linting command. 102 | go tool golangci-lint run ./... 103 | 104 | .PHONY: check 105 | check: ## Runs static analysis tools. 106 | go tool govulncheck ./... 107 | go tool betteralign ./... 108 | go vet ./... 109 | 110 | .PHONY: fix 111 | fix: ## Fixes code formatting and alignment. 112 | go tool betteralign -apply ./... 113 | go fmt ./... 114 | 115 | .PHONY: postgres-start 116 | postgres-start: ## Starts the postgres container. 117 | docker compose --file ./ops/docker/compose.yml up --detach postgres 118 | 119 | .PHONY: postgres-stop 120 | postgres-stop: ## Stops the postgres container. 121 | docker compose --file ./ops/docker/compose.yml stop postgres 122 | 123 | .PHONY: container-start 124 | container-start: ## Starts the container. 125 | docker compose --file ./ops/docker/compose.yml up --detach sample 126 | 127 | .PHONY: container-rebuild 128 | container-rebuild: ## Rebuilds the container. 129 | docker compose --file ./ops/docker/compose.yml up --detach --build sample 130 | 131 | .PHONY: container-restart 132 | container-restart: ## Restarts the container. 133 | docker compose --file ./ops/docker/compose.yml restart sample 134 | 135 | .PHONY: container-stop 136 | container-stop: ## Stops the container. 137 | docker compose --file ./ops/docker/compose.yml stop sample 138 | 139 | .PHONY: container-destroy 140 | container-destroy: ## Destroys the container. 141 | docker compose --file ./ops/docker/compose.yml down sample 142 | 143 | .PHONY: container-update 144 | container-update: ## Updates the container. 145 | docker compose --file ./ops/docker/compose.yml pull sample 146 | 147 | .PHONY: container-dev 148 | container-dev: ## Watches the container. 149 | docker compose --file ./ops/docker/compose.yml watch sample 150 | 151 | .PHONY: container-logs 152 | container-logs: ## Shows the logs of the container. 153 | docker compose --file ./ops/docker/compose.yml logs sample 154 | 155 | .PHONY: container-cli 156 | container-cli: ## Opens a shell in the container. 157 | docker compose --file ./ops/docker/compose.yml exec sample bash 158 | 159 | .PHONY: generate-proto 160 | generate-proto: ## Generates the proto stubs. 161 | @{ \ 162 | for f in ./specs/proto/*; do \ 163 | current_proto="$$(basename $$f)"; \ 164 | echo "Generating stubs for $$current_proto"; \ 165 | \ 166 | protoc --proto_path=./specs/proto/ \ 167 | --go_out=./pkg/proto-go/ --go_opt=paths=source_relative \ 168 | --go-grpc_out=./pkg/proto-go/ --go-grpc_opt=paths=source_relative \ 169 | "./specs/proto/$$current_proto/$$current_proto.proto"; \ 170 | done \ 171 | } 172 | 173 | %: 174 | @: 175 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang Service Template 2 | 3 | `Golang Service Template` project is designed to provide a robust foundation 4 | that is always ready to be open-sourced, accelerating development and fostering 5 | a unified understanding across disciplines. It empowers teams to quickly adopt 6 | best practices and streamline the project setup, ensuring consistency and 7 | clarity from the very start. 8 | 9 | 10 | ## Structure 11 | 12 | This project inherits the 13 | [Standard Go Project Layout](https://github.com/golang-standards/project-layout) 14 | structure but includes its own interpretation. 15 | 16 | The template code also serves as a service template, implemented with Hexagonal 17 | Architecture to support typical software organizations striving to apply 18 | Event-Driven Architecture (EDA) and Domain-Driven Design (DDD). 19 | 20 | The decision to use Hexagonal Architecture is based on its simplicity as one of 21 | the most straightforward implementations of Onion Architecture, with which I 22 | have extensive experience. Additionally, it is flexible enough to evolve into 23 | more structured or complex systems, such as Clean Architecture, as project 24 | requirements grow. 25 | 26 | 27 | ## Hexagonal Architecture Overview 28 | 29 | This project follows hexagonal architecture principles, also known as ports and adapters pattern: 30 | 31 | ### Business Logic (`pkg/sample/business/`) 32 | - Contains domain entities and business rules 33 | - Defines interfaces (ports) that the outside world must implement 34 | - No external dependencies, pure business logic 35 | - Example: `channels.Service` interface in `pkg/sample/business/channels/service.go` 36 | 37 | ### Adapters (`pkg/sample/adapters/`) 38 | - Implements interfaces defined by the business logic 39 | - Handles external concerns (HTTP, GRPC, database, etc.) 40 | - Organized by technology/concern: 41 | - `appcontext/`: Application configuration and context 42 | - `storage/`: Database repositories 43 | - `http/`: HTTP server and handlers 44 | - `grpc/`: GRPC server and handlers 45 | 46 | 47 | ## Directories 48 | 49 | ``` 50 | . 51 | ├── cmd/ # Application entry points 52 | │ ├── migrate/ # Database migration tool (based on goose) 53 | │ ├── manage/ # Manages codebase and app-related resources 54 | │ └── serve/ # Main service entry point 55 | ├── pkg/ 56 | │ └── sample/ # Our application code 57 | │ ├── adapters/ # Implementation of ports (adapters) 58 | │ │ ├── appcontext/ # Application context and configuration 59 | │ │ ├── http/ # HTTP server and handlers 60 | │ │ ├── grpc/ # GRPC server and handlers 61 | │ │ └── storage/ # Database repositories 62 | │ └── business/ # Business logic and domain models 63 | │ ├── channels/ # Channel-related business objects 64 | │ └── tenants/ # Tenant-related business objects 65 | ├── etc/ 66 | │ └── data/ # Data source-related files 67 | │ └── default/ # Data source name 68 | │ ├── migrations/ # SQL migration files 69 | │ └── queries/ # SQL query definitions 70 | └── ops/ # Operational configurations 71 | └── docker/ # Docker-related files 72 | ``` 73 | 74 | ## Installation 75 | 76 | - 1️⃣ Ensure that `golang` tools are _properly_ installed on your machine 77 | 78 | ```bash 79 | $ go version 80 | go version go0.0.0 os/arch64 81 | 82 | $ go env GOPATH 83 | ~/go/0.0.0/packages 84 | ``` 85 | 86 | **Important rules:** 87 | - `GOPATH` envvar must be set to output of `go env GOPATH` 88 | - `$GOPATH/bin` must be included to your `PATH` envvar 89 | 90 | So, your `~/.zprofile` should include something like this: 91 | 92 | ``` 93 | export GOPATH="$(go env GOPATH)" 94 | export PATH="$PATH:$GOPATH/bin" 95 | ``` 96 | 97 | - 2️⃣ Install prerequisites 98 | 99 | **On macOS and Homebrew (automatically):** 100 | 101 | ```bash 102 | $ make init 103 | ``` 104 | 105 | If it fails on any step, you can install them manually by following the steps 106 | below. Otherwise, you can skip the rest of the steps. 107 | 108 | **On other OS or without Homebrew:** 109 | 110 | - Install and enable [pre-commit](https://pre-commit.com/#install) 111 | - Install [GNU make](https://www.gnu.org/software/make/) 112 | - Install [act](https://nektosact.com/installation/index.html) 113 | - Install [protobuf](https://github.com/protocolbuffers/protobuf/releases) 114 | - Install [Air](https://github.com/air-verse/air#installation) 115 | - Install generators and checkers via `go tool` 116 | 117 | ```bash 118 | $ brew install pre-commit 119 | ==> Fetching dependencies for pre-commit 120 | ==> Fetching pre-commit 121 | ==> Installing dependencies for pre-commit 122 | ==> Installing pre-commit 123 | ... 124 | 125 | $ pre-commit install 126 | pre-commit installed at .git/hooks/pre-commit 127 | 128 | $ brew install make 129 | ==> Fetching dependencies for make 130 | ==> Fetching make 131 | ==> Installing dependencies for make 132 | ==> Installing make 133 | ... 134 | 135 | $ brew install act 136 | ==> Fetching dependencies for act 137 | ==> Fetching act 138 | ==> Installing dependencies for act 139 | ==> Installing act 140 | ... 141 | 142 | $ brew install protobuf 143 | ==> Fetching dependencies for protobuf 144 | ==> Fetching protobuf 145 | ==> Installing dependencies for protobuf 146 | ==> Installing protobuf 147 | ... 148 | 149 | $ make init-generators 150 | go: downloading github.com/sqlc-dev/sqlc/cmd/sqlc v0.0.0 151 | go: downloading github.com/vektra/mockery/v2 v0.0.0 152 | go: downloading golang.org/x/tools/cmd/stringer v0.0.0 153 | go: downloading github.com/jandelgado/gcov2lcov v0.0.0 154 | go: downloading google.golang.org/protobuf/cmd/protoc-gen-go v0.0.0 155 | go: downloading google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0 156 | 157 | $ make init-checkers 158 | go: downloading github.com/golangci/golangci-lint/cmd/golangci-lint v0.0.0 159 | go: downloading github.com/dkorunic/betteralign/cmd/betteralign v0.0.0 160 | go: downloading golang.org/x/vuln/cmd/govulncheck v0.0.0 161 | ``` 162 | 163 | - 3️⃣ (Optional) Ensure that you can access private dependencies 164 | 165 | You need to get a Personal Access Token from your GitHub account in order to 166 | download private dependencies. 167 | 168 | To get these, visit https://github.com/settings/tokens/new and create a new 169 | token with the `read:packages` scope. 170 | 171 | Then, you need to create or edit the `.netrc` file in your home directory with 172 | the following content: 173 | 174 | ``` 175 | machine github.com login password 176 | ``` 177 | 178 | - 4️⃣ Download required modules for the project 179 | 180 | ```bash 181 | $ make dep 182 | ``` 183 | 184 | - 5️⃣ (Optional) Check installation via pre-commit scripts 185 | 186 | ```bash 187 | $ pre-commit run --all-files 188 | ``` 189 | 190 | ## Execution 191 | 192 | ### Running the project 193 | 194 | Before running any command, please make sure that you have configured your 195 | environment regarding your own settings first. You may found the related entries 196 | that can be configured in `.env` file. 197 | 198 | ```bash 199 | $ make run 200 | 02:27:53.026 INFO adding datasource connection {"name":"default","dialect":"postgres"} 201 | 02:27:53.563 INFO successfully added datasource connection {"name":"default"} 202 | 02:27:53.563 INFO Starting service {"name":"sample","environment":"development","features":{"Dummy":true}} 203 | 02:27:53.564 INFO HttpService is starting... {"addr":":8080"} 204 | ``` 205 | 206 | - You can access http://localhost:8080/ to check if the project is running 207 | 208 | ## Running the project (with hot-reloading development mode) 209 | 210 | ```bash 211 | $ make dev 212 | ``` 213 | 214 | ## Testing the project 215 | 216 | ```bash 217 | $ make test 218 | ``` 219 | 220 | ## Development (with Docker Compose) 221 | 222 | ```bash 223 | # first start freshly built containers in background (daemon mode) 224 | $ make container-start 225 | 226 | # then launch watch mode to reflect changes on time 227 | $ make container-dev 228 | ``` 229 | 230 | ## Contribution 231 | 232 | - Create a new branch for your feature 233 | - Make your changes 234 | - Test your changes (see [Execution](#execution) below) 235 | - Commit your changes 236 | - Push your changes to your branch 237 | - Create a pull request to the `main` branch 238 | - Wait for review and merge 239 | - Delete your branch 240 | 241 | 242 | ## More Information 243 | 244 | This project is bootstrapped from 245 | https://github.com/eser/golang-service-template. See the source repository for 246 | further details. 247 | 248 | 249 | ## License 250 | 251 | This project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details. 252 | -------------------------------------------------------------------------------- /bin/sqlc-gen-go.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eser/golang-service-template/d3ffc6feecf25585c117ecf48f817d606696d2e0/bin/sqlc-gen-go.wasm -------------------------------------------------------------------------------- /cmd/manage/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/eser/go-service/cmd/manage/subcommands" 5 | "github.com/spf13/cobra" 6 | ) 7 | 8 | func main() { 9 | rootCmd := &cobra.Command{ //nolint:exhaustruct 10 | Use: "esimcli", 11 | Short: "eSIM CLI for eSIM management", 12 | Long: `eSIM CLI provides various functionalities for eSIM management including reporting and administration.`, 13 | } 14 | 15 | rootCmd.AddCommand(subcommands.CmdHealthCheck()) 16 | 17 | err := rootCmd.Execute() 18 | if err != nil { 19 | panic(err) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cmd/manage/subcommands/healthcheck.go: -------------------------------------------------------------------------------- 1 | package subcommands 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/eser/go-service/pkg/sample/adapters/appcontext" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | func CmdHealthCheck() *cobra.Command { 12 | healthCheckCmd := &cobra.Command{ //nolint:exhaustruct 13 | Use: "healthcheck", 14 | Short: "Check the health of the database", 15 | Long: `Check the health of the database`, 16 | RunE: func(cmd *cobra.Command, args []string) error { 17 | return execHealthCheck(cmd.Context()) 18 | }, 19 | } 20 | 21 | return healthCheckCmd 22 | } 23 | 24 | func execHealthCheck(ctx context.Context) error { 25 | _, err := appcontext.NewAppContext(ctx) 26 | if err != nil { 27 | return err //nolint:wrapcheck 28 | } 29 | 30 | fmt.Println("Health check passed") //nolint:forbidigo 31 | 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /cmd/migrate/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "errors" 7 | "fmt" 8 | "os" 9 | 10 | "github.com/eser/go-service/pkg/sample/adapters/appcontext" 11 | "github.com/pressly/goose/v3" 12 | ) 13 | 14 | var ( 15 | ErrDatasourceNameRequired = errors.New("data source name is required") 16 | ErrCommandRequired = errors.New("command is required") 17 | ErrAppContextNotInitialized = errors.New("app context is not initialized") 18 | ErrDatasourceNotInitialized = errors.New("data source is not initialized") 19 | ErrDatasourceNotSqlDb = errors.New("data source is not an instance of *sql.DB") 20 | ErrFailedToRunGoose = errors.New("failed to run goose") 21 | ) 22 | 23 | func run(ctx context.Context, args []string) error { 24 | if len(args) < 1 { 25 | return ErrDatasourceNameRequired 26 | } 27 | 28 | if len(args) < 2 { //nolint:mnd 29 | return ErrCommandRequired 30 | } 31 | 32 | datasourceName := args[0] 33 | command := args[1] 34 | rest := args[2:] 35 | 36 | appContext, err := appcontext.NewAppContext(ctx) 37 | if err != nil { 38 | return fmt.Errorf("%w: %w", ErrAppContextNotInitialized, err) 39 | } 40 | 41 | datasource := appContext.Data.GetNamed(datasourceName) 42 | if datasource == nil { 43 | return ErrDatasourceNotInitialized 44 | } 45 | 46 | db, dbOk := datasource.GetConnection().(*sql.DB) //nolint:varnamelen 47 | if !dbOk { 48 | return ErrDatasourceNotSqlDb 49 | } 50 | 51 | dialect := string(datasource.GetDialect()) 52 | 53 | err = goose.SetDialect(dialect) 54 | if err != nil { 55 | return fmt.Errorf("%w: %w", ErrFailedToRunGoose, err) 56 | } 57 | 58 | migrationsPath := fmt.Sprintf("./etc/data/%s/migrations", datasourceName) 59 | 60 | err = goose.RunContext(ctx, command, db, migrationsPath, rest...) 61 | if err != nil { 62 | return fmt.Errorf("%w: %w", ErrFailedToRunGoose, err) 63 | } 64 | 65 | return nil 66 | } 67 | 68 | func main() { 69 | ctx := context.Background() 70 | 71 | err := run(ctx, os.Args[1:]) 72 | if err != nil { 73 | panic(err) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /cmd/serve/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log/slog" 6 | 7 | "github.com/eser/go-service/pkg/sample/adapters/appcontext" 8 | "github.com/eser/go-service/pkg/sample/adapters/http" 9 | ) 10 | 11 | func main() { 12 | ctx := context.Background() 13 | 14 | appContext, err := appcontext.NewAppContext(ctx) 15 | if err != nil { 16 | panic(err) 17 | } 18 | 19 | appContext.Logger.InfoContext( 20 | ctx, 21 | "Starting service", 22 | slog.String("name", appContext.Config.AppName), 23 | slog.String("environment", appContext.Config.AppEnv), 24 | slog.Any("features", appContext.Config.Features), 25 | ) 26 | 27 | err = http.Run(ctx, &appContext.Config.Http, appContext.Metrics, appContext.Logger, appContext.Data) 28 | if err != nil { 29 | panic(err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample", 3 | "features": { 4 | "dummy": true 5 | }, 6 | "data": { 7 | "sources": { 8 | "default": { 9 | "dsn": "postgres://postgres:s3cr3t@localhost:5432/postgres?sslmode=disable" 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /etc/data/default/migrations/0001_create_channels.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | CREATE TABLE channel ( 3 | id TEXT PRIMARY KEY, 4 | name TEXT 5 | ); 6 | 7 | INSERT INTO channel VALUES 8 | ('telegram', 'Telegram'), 9 | ('whatsapp', 'WhatsApp'); 10 | 11 | -- +goose Down 12 | DROP TABLE channel; 13 | -------------------------------------------------------------------------------- /etc/data/default/queries/channels.sql: -------------------------------------------------------------------------------- 1 | -- name: GetChannelById :one 2 | select * from "channel" 3 | where id = $1; 4 | 5 | -- name: GetChannelByName :one 6 | select * from "channel" 7 | where name = $1; 8 | 9 | -- name: ListChannels :many 10 | select * from "channel"; 11 | 12 | -- name: CreateChannel :one 13 | insert into "channel" (id, name) 14 | values ($1, $2) returning *; 15 | 16 | -- name: UpdateChannel :execrows 17 | update "channel" 18 | set name = $2 19 | where id = $1; 20 | 21 | -- name: DeleteChannel :execrows 22 | delete from "channel" 23 | where id = $1; 24 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/eser/go-service 2 | 3 | go 1.24.2 4 | 5 | require ( 6 | github.com/eser/ajan v0.6.28 7 | github.com/pressly/goose/v3 v3.24.3 8 | github.com/spf13/cobra v1.9.1 9 | google.golang.org/grpc v1.72.2 10 | google.golang.org/protobuf v1.36.6 11 | ) 12 | 13 | require ( 14 | 4d63.com/gocheckcompilerdirectives v1.3.0 // indirect 15 | 4d63.com/gochecknoglobals v0.2.2 // indirect 16 | cel.dev/expr v0.20.0 // indirect 17 | dario.cat/mergo v1.0.1 // indirect 18 | filippo.io/edwards25519 v1.1.0 // indirect 19 | github.com/4meepo/tagalign v1.4.2 // indirect 20 | github.com/Abirdcfly/dupword v0.1.3 // indirect 21 | github.com/Antonboom/errname v1.0.0 // indirect 22 | github.com/Antonboom/nilnil v1.0.1 // indirect 23 | github.com/Antonboom/testifylint v1.5.2 // indirect 24 | github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect 25 | github.com/Crocmagnon/fatcontext v0.7.1 // indirect 26 | github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect 27 | github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 // indirect 28 | github.com/KimMachineGun/automemlimit v0.7.1 // indirect 29 | github.com/Masterminds/semver/v3 v3.3.0 // indirect 30 | github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect 31 | github.com/air-verse/air v1.61.7 // indirect 32 | github.com/alecthomas/go-check-sumtype v0.3.1 // indirect 33 | github.com/alexkohler/nakedret/v2 v2.0.5 // indirect 34 | github.com/alexkohler/prealloc v1.0.0 // indirect 35 | github.com/alingse/asasalint v0.0.11 // indirect 36 | github.com/alingse/nilnesserr v0.1.2 // indirect 37 | github.com/antlr4-go/antlr/v4 v4.13.1 // indirect 38 | github.com/ashanbrown/forbidigo v1.6.0 // indirect 39 | github.com/ashanbrown/makezero v1.2.0 // indirect 40 | github.com/beorn7/perks v1.0.1 // indirect 41 | github.com/bep/godartsass v1.2.0 // indirect 42 | github.com/bep/godartsass/v2 v2.1.0 // indirect 43 | github.com/bep/golibsass v1.2.0 // indirect 44 | github.com/bkielbasa/cyclop v1.2.3 // indirect 45 | github.com/blizzy78/varnamelen v0.8.0 // indirect 46 | github.com/bombsimon/wsl/v4 v4.5.0 // indirect 47 | github.com/breml/bidichk v0.3.2 // indirect 48 | github.com/breml/errchkjson v0.4.0 // indirect 49 | github.com/butuzov/ireturn v0.3.1 // indirect 50 | github.com/butuzov/mirror v1.3.0 // indirect 51 | github.com/catenacyber/perfsprint v0.8.2 // indirect 52 | github.com/ccojocar/zxcvbn-go v1.0.2 // indirect 53 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 54 | github.com/charithe/durationcheck v0.0.10 // indirect 55 | github.com/chavacava/garif v0.1.0 // indirect 56 | github.com/chigopher/pathlib v0.19.1 // indirect 57 | github.com/ckaznocha/intrange v0.3.0 // indirect 58 | github.com/cli/safeexec v1.0.1 // indirect 59 | github.com/creack/pty v1.1.23 // indirect 60 | github.com/cubicdaiya/gonp v1.0.4 // indirect 61 | github.com/curioswitch/go-reassign v0.3.0 // indirect 62 | github.com/daixiang0/gci v0.13.5 // indirect 63 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 64 | github.com/denis-tingaikin/go-header v0.5.0 // indirect 65 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 66 | github.com/dkorunic/betteralign v0.7.0 // indirect 67 | github.com/dustin/go-humanize v1.0.1 // indirect 68 | github.com/ettle/strcase v0.2.0 // indirect 69 | github.com/fatih/color v1.18.0 // indirect 70 | github.com/fatih/structtag v1.2.0 // indirect 71 | github.com/firefart/nonamedreturns v1.0.5 // indirect 72 | github.com/fsnotify/fsnotify v1.8.0 // indirect 73 | github.com/fzipp/gocyclo v0.6.0 // indirect 74 | github.com/getkin/kin-openapi v0.132.0 // indirect 75 | github.com/ghostiam/protogetter v0.3.9 // indirect 76 | github.com/go-critic/go-critic v0.12.0 // indirect 77 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 78 | github.com/go-openapi/swag v0.23.0 // indirect 79 | github.com/go-sql-driver/mysql v1.9.2 // indirect 80 | github.com/go-toolsmith/astcast v1.1.0 // indirect 81 | github.com/go-toolsmith/astcopy v1.1.0 // indirect 82 | github.com/go-toolsmith/astequal v1.2.0 // indirect 83 | github.com/go-toolsmith/astfmt v1.1.0 // indirect 84 | github.com/go-toolsmith/astp v1.1.0 // indirect 85 | github.com/go-toolsmith/strparse v1.1.0 // indirect 86 | github.com/go-toolsmith/typep v1.1.0 // indirect 87 | github.com/go-viper/mapstructure/v2 v2.2.1 // indirect 88 | github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect 89 | github.com/gobwas/glob v0.2.3 // indirect 90 | github.com/gofrs/flock v0.12.1 // indirect 91 | github.com/gohugoio/hugo v0.134.3 // indirect 92 | github.com/golang-jwt/jwt/v5 v5.2.2 // indirect 93 | github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect 94 | github.com/golangci/go-printf-func-name v0.1.0 // indirect 95 | github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect 96 | github.com/golangci/golangci-lint v1.64.8 // indirect 97 | github.com/golangci/misspell v0.6.0 // indirect 98 | github.com/golangci/plugin-module-register v0.1.1 // indirect 99 | github.com/golangci/revgrep v0.8.0 // indirect 100 | github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect 101 | github.com/google/cel-go v0.24.1 // indirect 102 | github.com/google/go-cmp v0.7.0 // indirect 103 | github.com/google/renameio/v2 v2.0.0 // indirect 104 | github.com/google/uuid v1.6.0 // indirect 105 | github.com/gordonklaus/ineffassign v0.1.0 // indirect 106 | github.com/gostaticanalysis/analysisutil v0.7.1 // indirect 107 | github.com/gostaticanalysis/comment v1.5.0 // indirect 108 | github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect 109 | github.com/gostaticanalysis/nilerr v0.1.1 // indirect 110 | github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect 111 | github.com/hashicorp/go-version v1.7.0 // indirect 112 | github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect 113 | github.com/hexops/gotextdiff v1.0.3 // indirect 114 | github.com/huandu/xstrings v1.4.0 // indirect 115 | github.com/iancoleman/strcase v0.3.0 // indirect 116 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 117 | github.com/jackc/pgpassfile v1.0.0 // indirect 118 | github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect 119 | github.com/jackc/pgx/v5 v5.7.4 // indirect 120 | github.com/jackc/puddle/v2 v2.2.2 // indirect 121 | github.com/jandelgado/gcov2lcov v1.1.1 // indirect 122 | github.com/jgautheron/goconst v1.7.1 // indirect 123 | github.com/jingyugao/rowserrcheck v1.1.1 // indirect 124 | github.com/jinzhu/copier v0.4.0 // indirect 125 | github.com/jinzhu/inflection v1.0.0 // indirect 126 | github.com/jjti/go-spancheck v0.6.4 // indirect 127 | github.com/josharian/intern v1.0.0 // indirect 128 | github.com/julz/importas v0.2.0 // indirect 129 | github.com/karamaru-alpha/copyloopvar v1.2.1 // indirect 130 | github.com/kisielk/errcheck v1.9.0 // indirect 131 | github.com/kkHAIKE/contextcheck v1.1.6 // indirect 132 | github.com/kulti/thelper v0.6.3 // indirect 133 | github.com/kunwardeep/paralleltest v1.0.10 // indirect 134 | github.com/lasiar/canonicalheader v1.1.2 // indirect 135 | github.com/ldez/exptostd v0.4.2 // indirect 136 | github.com/ldez/gomoddirectives v0.6.1 // indirect 137 | github.com/ldez/grignotin v0.9.0 // indirect 138 | github.com/ldez/tagliatelle v0.7.1 // indirect 139 | github.com/ldez/usetesting v0.4.2 // indirect 140 | github.com/leonklingele/grouper v1.1.2 // indirect 141 | github.com/macabu/inamedparam v0.1.3 // indirect 142 | github.com/mailru/easyjson v0.7.7 // indirect 143 | github.com/maratori/testableexamples v1.0.0 // indirect 144 | github.com/maratori/testpackage v1.1.1 // indirect 145 | github.com/matoous/godox v1.1.0 // indirect 146 | github.com/mattn/go-colorable v0.1.14 // indirect 147 | github.com/mattn/go-isatty v0.0.20 // indirect 148 | github.com/mattn/go-runewidth v0.0.16 // indirect 149 | github.com/mfridman/interpolate v0.0.2 // indirect 150 | github.com/mgechev/revive v1.7.0 // indirect 151 | github.com/mitchellh/go-homedir v1.1.0 // indirect 152 | github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c // indirect 153 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect 154 | github.com/moricho/tparallel v0.3.2 // indirect 155 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 156 | github.com/nakabonne/nestif v0.3.1 // indirect 157 | github.com/ncruces/go-strftime v0.1.9 // indirect 158 | github.com/nishanths/exhaustive v0.12.0 // indirect 159 | github.com/nishanths/predeclared v0.2.2 // indirect 160 | github.com/nunnatsa/ginkgolinter v0.19.1 // indirect 161 | github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect 162 | github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect 163 | github.com/oklog/ulid/v2 v2.1.0 // indirect 164 | github.com/olekukonko/tablewriter v0.0.5 // indirect 165 | github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect 166 | github.com/pelletier/go-toml v1.9.5 // indirect 167 | github.com/pelletier/go-toml/v2 v2.2.3 // indirect 168 | github.com/perimeterx/marshmallow v1.1.5 // indirect 169 | github.com/pganalyze/pg_query_go/v6 v6.1.0 // indirect 170 | github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb // indirect 171 | github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 // indirect 172 | github.com/pingcap/log v1.1.0 // indirect 173 | github.com/pingcap/tidb/pkg/parser v0.0.0-20250324122243-d51e00e5bbf0 // indirect 174 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 175 | github.com/polyfloyd/go-errorlint v1.7.1 // indirect 176 | github.com/prometheus/client_golang v1.22.0 // indirect 177 | github.com/prometheus/client_model v0.6.2 // indirect 178 | github.com/prometheus/common v0.63.0 // indirect 179 | github.com/prometheus/procfs v0.16.1 // indirect 180 | github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect 181 | github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect 182 | github.com/quasilyte/gogrep v0.5.0 // indirect 183 | github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect 184 | github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect 185 | github.com/rabbitmq/amqp091-go v1.10.0 // indirect 186 | github.com/raeperd/recvcheck v0.2.0 // indirect 187 | github.com/redis/go-redis/v9 v9.8.0 // indirect 188 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect 189 | github.com/rivo/uniseg v0.4.7 // indirect 190 | github.com/riza-io/grpc-go v0.2.0 // indirect 191 | github.com/rogpeppe/go-internal v1.14.1 // indirect 192 | github.com/rs/zerolog v1.33.0 // indirect 193 | github.com/ryancurrah/gomodguard v1.3.5 // indirect 194 | github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect 195 | github.com/sagikazarmark/locafero v0.7.0 // indirect 196 | github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect 197 | github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect 198 | github.com/sashamelentyev/interfacebloat v1.1.0 // indirect 199 | github.com/sashamelentyev/usestdlibvars v1.28.0 // indirect 200 | github.com/securego/gosec/v2 v2.22.2 // indirect 201 | github.com/sethvargo/go-retry v0.3.0 // indirect 202 | github.com/sirkon/dst v0.26.4 // indirect 203 | github.com/sirupsen/logrus v1.9.3 // indirect 204 | github.com/sivchari/containedctx v1.0.3 // indirect 205 | github.com/sivchari/tenv v1.12.1 // indirect 206 | github.com/sonatard/noctx v0.1.0 // indirect 207 | github.com/sourcegraph/conc v0.3.0 // indirect 208 | github.com/sourcegraph/go-diff v0.7.0 // indirect 209 | github.com/spf13/afero v1.12.0 // indirect 210 | github.com/spf13/cast v1.7.1 // indirect 211 | github.com/spf13/pflag v1.0.6 // indirect 212 | github.com/spf13/viper v1.20.0 // indirect 213 | github.com/sqlc-dev/sqlc v1.29.0 // indirect 214 | github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect 215 | github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect 216 | github.com/stoewer/go-strcase v1.2.0 // indirect 217 | github.com/stretchr/objx v0.5.2 // indirect 218 | github.com/stretchr/testify v1.10.0 // indirect 219 | github.com/subosito/gotenv v1.6.0 // indirect 220 | github.com/tdakkota/asciicheck v0.4.1 // indirect 221 | github.com/tdewolff/parse/v2 v2.7.15 // indirect 222 | github.com/tetafro/godot v1.5.0 // indirect 223 | github.com/tetratelabs/wazero v1.9.0 // indirect 224 | github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 // indirect 225 | github.com/timonwong/loggercheck v0.10.1 // indirect 226 | github.com/tomarrell/wrapcheck/v2 v2.10.0 // indirect 227 | github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect 228 | github.com/ultraware/funlen v0.2.0 // indirect 229 | github.com/ultraware/whitespace v0.2.0 // indirect 230 | github.com/uudashr/gocognit v1.2.0 // indirect 231 | github.com/uudashr/iface v1.3.1 // indirect 232 | github.com/vektra/mockery/v2 v2.53.3 // indirect 233 | github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07 // indirect 234 | github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 // indirect 235 | github.com/xen0n/gosmopolitan v1.2.2 // indirect 236 | github.com/yagipy/maintidx v1.0.0 // indirect 237 | github.com/yeya24/promlinter v0.3.0 // indirect 238 | github.com/ykadowak/zerologlint v0.1.5 // indirect 239 | gitlab.com/bosi/decorder v0.4.2 // indirect 240 | go-simpler.org/musttag v0.13.0 // indirect 241 | go-simpler.org/sloglint v0.9.0 // indirect 242 | go.uber.org/atomic v1.11.0 // indirect 243 | go.uber.org/automaxprocs v1.6.0 // indirect 244 | go.uber.org/multierr v1.11.0 // indirect 245 | go.uber.org/zap v1.27.0 // indirect 246 | golang.org/x/crypto v0.38.0 // indirect 247 | golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect 248 | golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect 249 | golang.org/x/mod v0.24.0 // indirect 250 | golang.org/x/net v0.40.0 // indirect 251 | golang.org/x/sync v0.14.0 // indirect 252 | golang.org/x/sys v0.33.0 // indirect 253 | golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 // indirect 254 | golang.org/x/term v0.32.0 // indirect 255 | golang.org/x/text v0.25.0 // indirect 256 | golang.org/x/tools v0.33.0 // indirect 257 | golang.org/x/vuln v1.1.4 // indirect 258 | google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect 259 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect 260 | google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect 261 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect 262 | gopkg.in/yaml.v2 v2.4.0 // indirect 263 | gopkg.in/yaml.v3 v3.0.1 // indirect 264 | honnef.co/go/tools v0.6.1 // indirect 265 | modernc.org/libc v1.65.0 // indirect 266 | modernc.org/mathutil v1.7.1 // indirect 267 | modernc.org/memory v1.10.0 // indirect 268 | modernc.org/sqlite v1.37.0 // indirect 269 | mvdan.cc/gofumpt v0.7.0 // indirect 270 | mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect 271 | ) 272 | 273 | tool ( 274 | github.com/air-verse/air 275 | github.com/dkorunic/betteralign/cmd/betteralign 276 | github.com/golangci/golangci-lint/cmd/golangci-lint 277 | github.com/jandelgado/gcov2lcov 278 | github.com/sqlc-dev/sqlc/cmd/sqlc 279 | github.com/vektra/mockery/v2 280 | golang.org/x/tools/cmd/stringer 281 | golang.org/x/vuln/cmd/govulncheck 282 | google.golang.org/grpc/cmd/protoc-gen-go-grpc 283 | google.golang.org/protobuf/cmd/protoc-gen-go 284 | ) 285 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | 4d63.com/gocheckcompilerdirectives v1.3.0 h1:Ew5y5CtcAAQeTVKUVFrE7EwHMrTO6BggtEj8BZSjZ3A= 2 | 4d63.com/gocheckcompilerdirectives v1.3.0/go.mod h1:ofsJ4zx2QAuIP/NO/NAh1ig6R1Fb18/GI7RVMwz7kAY= 3 | 4d63.com/gochecknoglobals v0.2.2 h1:H1vdnwnMaZdQW/N+NrkT1SZMTBmcwHe9Vq8lJcYYTtU= 4 | 4d63.com/gochecknoglobals v0.2.2/go.mod h1:lLxwTQjL5eIesRbvnzIP3jZtG140FnTdz+AlMa+ogt0= 5 | cel.dev/expr v0.20.0 h1:OunBvVCfvpWlt4dN7zg3FM6TDkzOePe1+foGJ9AXeeI= 6 | cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= 7 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 8 | dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= 9 | dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 10 | filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= 11 | filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 12 | github.com/4meepo/tagalign v1.4.2 h1:0hcLHPGMjDyM1gHG58cS73aQF8J4TdVR96TZViorO9E= 13 | github.com/4meepo/tagalign v1.4.2/go.mod h1:+p4aMyFM+ra7nb41CnFG6aSDXqRxU/w1VQqScKqDARI= 14 | github.com/Abirdcfly/dupword v0.1.3 h1:9Pa1NuAsZvpFPi9Pqkd93I7LIYRURj+A//dFd5tgBeE= 15 | github.com/Abirdcfly/dupword v0.1.3/go.mod h1:8VbB2t7e10KRNdwTVoxdBaxla6avbhGzb8sCTygUMhw= 16 | github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoTBA= 17 | github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI= 18 | github.com/Antonboom/nilnil v1.0.1 h1:C3Tkm0KUxgfO4Duk3PM+ztPncTFlOf0b2qadmS0s4xs= 19 | github.com/Antonboom/nilnil v1.0.1/go.mod h1:CH7pW2JsRNFgEh8B2UaPZTEPhCMuFowP/e8Udp9Nnb0= 20 | github.com/Antonboom/testifylint v1.5.2 h1:4s3Xhuv5AvdIgbd8wOOEeo0uZG7PbDKQyKY5lGoQazk= 21 | github.com/Antonboom/testifylint v1.5.2/go.mod h1:vxy8VJ0bc6NavlYqjZfmp6EfqXMtBgQ4+mhCojwC1P8= 22 | github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69 h1:+tu3HOoMXB7RXEINRVIpxJCT+KdYiI7LAEAUrOw3dIU= 23 | github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69/go.mod h1:L1AbZdiDllfyYH5l5OkAaZtk7VkWe89bPJFmnDBNHxg= 24 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 25 | github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= 26 | github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= 27 | github.com/Crocmagnon/fatcontext v0.7.1 h1:SC/VIbRRZQeQWj/TcQBS6JmrXcfA+BU4OGSVUt54PjM= 28 | github.com/Crocmagnon/fatcontext v0.7.1/go.mod h1:1wMvv3NXEBJucFGfwOJBxSVWcoIO6emV215SMkW9MFU= 29 | github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= 30 | github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= 31 | github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 h1:Sz1JIXEcSfhz7fUi7xHnhpIE0thVASYjvosApmHuD2k= 32 | github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1/go.mod h1:n/LSCXNuIYqVfBlVXyHfMQkZDdp1/mmxfSjADd3z1Zg= 33 | github.com/KimMachineGun/automemlimit v0.7.1 h1:QcG/0iCOLChjfUweIMC3YL5Xy9C3VBeNmCZHrZfJMBw= 34 | github.com/KimMachineGun/automemlimit v0.7.1/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= 35 | github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= 36 | github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= 37 | github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsuj3piCMx4= 38 | github.com/OpenPeeDeeP/depguard/v2 v2.2.1/go.mod h1:q4DKzC4UcVaAvcfd41CZh0PWpGgzrVxUYBlgKNGquUo= 39 | github.com/air-verse/air v1.61.7 h1:MtOZs6wYoYYXm+S4e+ORjkq9BjvyEamKJsHcvko8LrQ= 40 | github.com/air-verse/air v1.61.7/go.mod h1:QW4HkIASdtSnwaYof1zgJCSxd41ebvix10t5ubtm9cg= 41 | github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= 42 | github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= 43 | github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= 44 | github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= 45 | github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= 46 | github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= 47 | github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= 48 | github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= 49 | github.com/alexkohler/nakedret/v2 v2.0.5 h1:fP5qLgtwbx9EJE8dGEERT02YwS8En4r9nnZ71RK+EVU= 50 | github.com/alexkohler/nakedret/v2 v2.0.5/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU= 51 | github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= 52 | github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= 53 | github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE= 54 | github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= 55 | github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQggTglU/0= 56 | github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8= 57 | github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= 58 | github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= 59 | github.com/alingse/nilnesserr v0.1.2 h1:Yf8Iwm3z2hUUrP4muWfW83DF4nE3r1xZ26fGWUKCZlo= 60 | github.com/alingse/nilnesserr v0.1.2/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= 61 | github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= 62 | github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= 63 | github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c h1:651/eoCRnQ7YtSjAnSzRucrJz+3iGEFt+ysraELS81M= 64 | github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 65 | github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= 66 | github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= 67 | github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9IEUU= 68 | github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4= 69 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 70 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 71 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 72 | github.com/bep/clocks v0.5.0 h1:hhvKVGLPQWRVsBP/UB7ErrHYIO42gINVbvqxvYTPVps= 73 | github.com/bep/clocks v0.5.0/go.mod h1:SUq3q+OOq41y2lRQqH5fsOoxN8GbxSiT6jvoVVLCVhU= 74 | github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= 75 | github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= 76 | github.com/bep/gitmap v1.6.0 h1:sDuQMm9HoTL0LtlrfxjbjgAg2wHQd4nkMup2FInYzhA= 77 | github.com/bep/gitmap v1.6.0/go.mod h1:n+3W1f/rot2hynsqEGxGMErPRgT41n9CkGuzPvz9cIw= 78 | github.com/bep/goat v0.5.0 h1:S8jLXHCVy/EHIoCY+btKkmcxcXFd34a0Q63/0D4TKeA= 79 | github.com/bep/goat v0.5.0/go.mod h1:Md9x7gRxiWKs85yHlVTvHQw9rg86Bm+Y4SuYE8CTH7c= 80 | github.com/bep/godartsass v1.2.0 h1:E2VvQrxAHAFwbjyOIExAMmogTItSKodoKuijNrGm5yU= 81 | github.com/bep/godartsass v1.2.0/go.mod h1:6LvK9RftsXMxGfsA0LDV12AGc4Jylnu6NgHL+Q5/pE8= 82 | github.com/bep/godartsass/v2 v2.1.0 h1:fq5Y1xYf4diu4tXABiekZUCA+5l/dmNjGKCeQwdy+s0= 83 | github.com/bep/godartsass/v2 v2.1.0/go.mod h1:AcP8QgC+OwOXEq6im0WgDRYK7scDsmZCEW62o1prQLo= 84 | github.com/bep/golibsass v1.2.0 h1:nyZUkKP/0psr8nT6GR2cnmt99xS93Ji82ZD9AgOK6VI= 85 | github.com/bep/golibsass v1.2.0/go.mod h1:DL87K8Un/+pWUS75ggYv41bliGiolxzDKWJAq3eJ1MA= 86 | github.com/bep/gowebp v0.4.0 h1:QihuVnvIKbRoeBNQkN0JPMM8ClLmD6V2jMftTFwSK3Q= 87 | github.com/bep/gowebp v0.4.0/go.mod h1:95gtYkAA8iIn1t3HkAPurRCVGV/6NhgaHJ1urz0iIwc= 88 | github.com/bep/imagemeta v0.8.1 h1:tjZLPRftjxU7PTI87o5e5WKOFQ4S9S0engiP1OTpJTI= 89 | github.com/bep/imagemeta v0.8.1/go.mod h1:5piPAq5Qomh07m/dPPCLN3mDJyFusvUG7VwdRD/vX0s= 90 | github.com/bep/lazycache v0.5.0 h1:9FJRrEp/s3BUpGEfTvLhmv50N4dXzoZnyRPU6NOUv0w= 91 | github.com/bep/lazycache v0.5.0/go.mod h1:NmRm7Dexh3pmR1EignYR8PjO2cWybFQ68+QgY3VMCSc= 92 | github.com/bep/logg v0.4.0 h1:luAo5mO4ZkhA5M1iDVDqDqnBBnlHjmtZF6VAyTp+nCQ= 93 | github.com/bep/logg v0.4.0/go.mod h1:Ccp9yP3wbR1mm++Kpxet91hAZBEQgmWgFgnXX3GkIV0= 94 | github.com/bep/overlayfs v0.9.2 h1:qJEmFInsW12L7WW7dOTUhnMfyk/fN9OCDEO5Gr8HSDs= 95 | github.com/bep/overlayfs v0.9.2/go.mod h1:aYY9W7aXQsGcA7V9x/pzeR8LjEgIxbtisZm8Q7zPz40= 96 | github.com/bep/tmc v0.5.1 h1:CsQnSC6MsomH64gw0cT5f+EwQDcvZz4AazKunFwTpuI= 97 | github.com/bep/tmc v0.5.1/go.mod h1:tGYHN8fS85aJPhDLgXETVKp+PR382OvFi2+q2GkGsq0= 98 | github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w= 99 | github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo= 100 | github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= 101 | github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= 102 | github.com/bombsimon/wsl/v4 v4.5.0 h1:iZRsEvDdyhd2La0FVi5k6tYehpOR/R7qIUjmKk7N74A= 103 | github.com/bombsimon/wsl/v4 v4.5.0/go.mod h1:NOQ3aLF4nD7N5YPXMruR6ZXDOAqLoM0GEpLwTdvmOSc= 104 | github.com/breml/bidichk v0.3.2 h1:xV4flJ9V5xWTqxL+/PMFF6dtJPvZLPsyixAoPe8BGJs= 105 | github.com/breml/bidichk v0.3.2/go.mod h1:VzFLBxuYtT23z5+iVkamXO386OB+/sVwZOpIj6zXGos= 106 | github.com/breml/errchkjson v0.4.0 h1:gftf6uWZMtIa/Is3XJgibewBm2ksAQSY/kABDNFTAdk= 107 | github.com/breml/errchkjson v0.4.0/go.mod h1:AuBOSTHyLSaaAFlWsRSuRBIroCh3eh7ZHh5YeelDIk8= 108 | github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= 109 | github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= 110 | github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= 111 | github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= 112 | github.com/butuzov/ireturn v0.3.1 h1:mFgbEI6m+9W8oP/oDdfA34dLisRFCj2G6o/yiI1yZrY= 113 | github.com/butuzov/ireturn v0.3.1/go.mod h1:ZfRp+E7eJLC0NQmk1Nrm1LOrn/gQlOykv+cVPdiXH5M= 114 | github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= 115 | github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= 116 | github.com/catenacyber/perfsprint v0.8.2 h1:+o9zVmCSVa7M4MvabsWvESEhpsMkhfE7k0sHNGL95yw= 117 | github.com/catenacyber/perfsprint v0.8.2/go.mod h1:q//VWC2fWbcdSLEY1R3l8n0zQCDPdE4IjZwyY1HMunM= 118 | github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg= 119 | github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= 120 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 121 | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 122 | github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 123 | github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= 124 | github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= 125 | github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= 126 | github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= 127 | github.com/chigopher/pathlib v0.19.1 h1:RoLlUJc0CqBGwq239cilyhxPNLXTK+HXoASGyGznx5A= 128 | github.com/chigopher/pathlib v0.19.1/go.mod h1:tzC1dZLW8o33UQpWkNkhvPwL5n4yyFRFm/jL1YGWFvY= 129 | github.com/ckaznocha/intrange v0.3.0 h1:VqnxtK32pxgkhJgYQEeOArVidIPg+ahLP7WBOXZd5ZY= 130 | github.com/ckaznocha/intrange v0.3.0/go.mod h1:+I/o2d2A1FBHgGELbGxzIcyd3/9l9DuwjM8FsbSS3Lo= 131 | github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= 132 | github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= 133 | github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= 134 | github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00= 135 | github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= 136 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 137 | github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 138 | github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 139 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 140 | github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= 141 | github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= 142 | github.com/cubicdaiya/gonp v1.0.4 h1:ky2uIAJh81WiLcGKBVD5R7KsM/36W6IqqTy6Bo6rGws= 143 | github.com/cubicdaiya/gonp v1.0.4/go.mod h1:iWGuP/7+JVTn02OWhRemVbMmG1DOUnmrGTYYACpOI0I= 144 | github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs= 145 | github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88= 146 | github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c= 147 | github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk= 148 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 149 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 150 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 151 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 152 | github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= 153 | github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= 154 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= 155 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= 156 | github.com/disintegration/gift v1.2.1 h1:Y005a1X4Z7Uc+0gLpSAsKhWi4qLtsdEcMIbbdvdZ6pc= 157 | github.com/disintegration/gift v1.2.1/go.mod h1:Jh2i7f7Q2BM7Ezno3PhfezbR1xpUg9dUg3/RlKGr4HI= 158 | github.com/dkorunic/betteralign v0.7.0 h1:kJ0OkCqZl0ggyL6Zpu80ai7jPlmjcZyju2OTfAWxdDE= 159 | github.com/dkorunic/betteralign v0.7.0/go.mod h1:lGScW+t8uN2ml0di76txaWuUDsolwUvwx8tPMGJfjy0= 160 | github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= 161 | github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= 162 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 163 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 164 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 165 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 166 | github.com/eser/ajan v0.6.28 h1:x4VIog/GzSdqPG/W4p/GPt9U7q/BzoaxF5ZvXO+oxe8= 167 | github.com/eser/ajan v0.6.28/go.mod h1:fKqIn/fdbRsqdJubbWMcjm4fJ+mxzg8ZgPZoDIs2xI0= 168 | github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= 169 | github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= 170 | github.com/evanw/esbuild v0.23.1 h1:ociewhY6arjTarKLdrXfDTgy25oxhTZmzP8pfuBTfTA= 171 | github.com/evanw/esbuild v0.23.1/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48= 172 | github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= 173 | github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= 174 | github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= 175 | github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= 176 | github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA= 177 | github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw= 178 | github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= 179 | github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= 180 | github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= 181 | github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 182 | github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= 183 | github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= 184 | github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= 185 | github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= 186 | github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= 187 | github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= 188 | github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= 189 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 190 | github.com/ghostiam/protogetter v0.3.9 h1:j+zlLLWzqLay22Cz/aYwTHKQ88GE2DQ6GkWSYFOI4lQ= 191 | github.com/ghostiam/protogetter v0.3.9/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA= 192 | github.com/go-critic/go-critic v0.12.0 h1:iLosHZuye812wnkEz1Xu3aBwn5ocCPfc9yqmFG9pa6w= 193 | github.com/go-critic/go-critic v0.12.0/go.mod h1:DpE0P6OVc6JzVYzmM5gq5jMU31zLr4am5mB/VfFK64w= 194 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 195 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 196 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 197 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 198 | github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= 199 | github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= 200 | github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= 201 | github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= 202 | github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= 203 | github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= 204 | github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU= 205 | github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= 206 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= 207 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= 208 | github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= 209 | github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= 210 | github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= 211 | github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= 212 | github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= 213 | github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= 214 | github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= 215 | github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= 216 | github.com/go-toolsmith/astequal v1.2.0 h1:3Fs3CYZ1k9Vo4FzFhwwewC3CHISHDnVUPC4x0bI2+Cw= 217 | github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY= 218 | github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= 219 | github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= 220 | github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= 221 | github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= 222 | github.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk= 223 | github.com/go-toolsmith/pkgload v1.2.2/go.mod h1:R2hxLNRKuAsiXCo2i5J6ZQPhnPMOVtU+f0arbFPWCus= 224 | github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= 225 | github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= 226 | github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= 227 | github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= 228 | github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= 229 | github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= 230 | github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 231 | github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY= 232 | github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= 233 | github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4= 234 | github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= 235 | github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= 236 | github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 237 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 238 | github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= 239 | github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= 240 | github.com/gohugoio/go-i18n/v2 v2.1.3-0.20230805085216-e63c13218d0e h1:QArsSubW7eDh8APMXkByjQWvuljwPGAGQpJEFn0F0wY= 241 | github.com/gohugoio/go-i18n/v2 v2.1.3-0.20230805085216-e63c13218d0e/go.mod h1:3Ltoo9Banwq0gOtcOwxuHG6omk+AwsQPADyw2vQYOJQ= 242 | github.com/gohugoio/hashstructure v0.1.0 h1:kBSTMLMyTXbrJVAxaKI+wv30MMJJxn9Q8kfQtJaZ400= 243 | github.com/gohugoio/hashstructure v0.1.0/go.mod h1:8ohPTAfQLTs2WdzB6k9etmQYclDUeNsIHGPAFejbsEA= 244 | github.com/gohugoio/httpcache v0.7.0 h1:ukPnn04Rgvx48JIinZvZetBfHaWE7I01JR2Q2RrQ3Vs= 245 | github.com/gohugoio/httpcache v0.7.0/go.mod h1:fMlPrdY/vVJhAriLZnrF5QpN3BNAcoBClgAyQd+lGFI= 246 | github.com/gohugoio/hugo v0.134.3 h1:Pn2KECXAAQWCd2uryDcmtzVhNJWGF5Pt6CplQvLcWe0= 247 | github.com/gohugoio/hugo v0.134.3/go.mod h1:/1gnGxlWfAzQarxcQ+tMvKw4e/IMBwy0DFbRxORwOtY= 248 | github.com/gohugoio/hugo-goldmark-extensions/extras v0.2.0 h1:MNdY6hYCTQEekY0oAfsxWZU1CDt6iH+tMLgyMJQh/sg= 249 | github.com/gohugoio/hugo-goldmark-extensions/extras v0.2.0/go.mod h1:oBdBVuiZ0fv9xd8xflUgt53QxW5jOCb1S+xntcN4SKo= 250 | github.com/gohugoio/hugo-goldmark-extensions/passthrough v0.3.0 h1:7PY5PIJ2mck7v6R52yCFvvYHvsPMEbulgRviw3I9lP4= 251 | github.com/gohugoio/hugo-goldmark-extensions/passthrough v0.3.0/go.mod h1:r8g5S7bHfdj0+9ShBog864ufCsVODKQZNjYYY8OnJpM= 252 | github.com/gohugoio/locales v0.14.0 h1:Q0gpsZwfv7ATHMbcTNepFd59H7GoykzWJIxi113XGDc= 253 | github.com/gohugoio/locales v0.14.0/go.mod h1:ip8cCAv/cnmVLzzXtiTpPwgJ4xhKZranqNqtoIu0b/4= 254 | github.com/gohugoio/localescompressed v1.0.1 h1:KTYMi8fCWYLswFyJAeOtuk/EkXR/KPTHHNN9OS+RTxo= 255 | github.com/gohugoio/localescompressed v1.0.1/go.mod h1:jBF6q8D7a0vaEmcWPNcAjUZLJaIVNiwvM3WlmTvooB0= 256 | github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= 257 | github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= 258 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 259 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 260 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 261 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 262 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 263 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 264 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 265 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 266 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 267 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 268 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 269 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 270 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 271 | github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 h1:WUvBfQL6EW/40l6OmeSBYQJNSif4O11+bmWEz+C7FYw= 272 | github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E= 273 | github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUPPyAKJuzv8pEJU= 274 | github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s= 275 | github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= 276 | github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= 277 | github.com/golangci/golangci-lint v1.64.8 h1:y5TdeVidMtBGG32zgSC7ZXTFNHrsJkDnpO4ItB3Am+I= 278 | github.com/golangci/golangci-lint v1.64.8/go.mod h1:5cEsUQBSr6zi8XI8OjmcY2Xmliqc4iYL7YoPrL+zLJ4= 279 | github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs= 280 | github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo= 281 | github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c= 282 | github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc= 283 | github.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s= 284 | github.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= 285 | github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs= 286 | github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ= 287 | github.com/google/cel-go v0.24.1 h1:jsBCtxG8mM5wiUJDSGUqU0K7Mtr3w7Eyv00rw4DiZxI= 288 | github.com/google/cel-go v0.24.1/go.mod h1:Hdf9TqOaTNSFQA1ybQaRqATVoK7m/zcf7IMhGXP5zI8= 289 | github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU= 290 | github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o= 291 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 292 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 293 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 294 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 295 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 296 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 297 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 298 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 299 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 300 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 301 | github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= 302 | github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 303 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 304 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 305 | github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= 306 | github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= 307 | github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= 308 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 309 | github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= 310 | github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= 311 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 312 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 313 | github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= 314 | github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= 315 | github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= 316 | github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= 317 | github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= 318 | github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= 319 | github.com/gostaticanalysis/comment v1.5.0 h1:X82FLl+TswsUMpMh17srGRuKaaXprTaytmEpgnKIDu8= 320 | github.com/gostaticanalysis/comment v1.5.0/go.mod h1:V6eb3gpCv9GNVqb6amXzEUX3jXLVK/AdA+IrAMSqvEc= 321 | github.com/gostaticanalysis/forcetypeassert v0.2.0 h1:uSnWrrUEYDr86OCxWa4/Tp2jeYDlogZiZHzGkWFefTk= 322 | github.com/gostaticanalysis/forcetypeassert v0.2.0/go.mod h1:M5iPavzE9pPqWyeiVXSFghQjljW1+l/Uke3PXHS6ILY= 323 | github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk= 324 | github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= 325 | github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= 326 | github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+3Zh0sUGqw8= 327 | github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs= 328 | github.com/hairyhenderson/go-codeowners v0.5.0 h1:dpQB+hVHiRc2VVvc2BHxkuM+tmu9Qej/as3apqUbsWc= 329 | github.com/hairyhenderson/go-codeowners v0.5.0/go.mod h1:R3uW1OQXEj2Gu6/OvZ7bt6hr0qdkLvUWPiqNaWnexpo= 330 | github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo= 331 | github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw= 332 | github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= 333 | github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 334 | github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 335 | github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= 336 | github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 337 | github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= 338 | github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= 339 | github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= 340 | github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= 341 | github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= 342 | github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 343 | github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= 344 | github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= 345 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 346 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 347 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 348 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 349 | github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= 350 | github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= 351 | github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg= 352 | github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= 353 | github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= 354 | github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= 355 | github.com/jandelgado/gcov2lcov v1.1.1 h1:CHUNoAglvb34DqmMoZchnzDbA3yjpzT8EoUvVqcAY+s= 356 | github.com/jandelgado/gcov2lcov v1.1.1/go.mod h1:tMVUlMVtS1po2SB8UkADWhOT5Y5Q13XOce2AYU69JuI= 357 | github.com/jdkato/prose v1.2.1 h1:Fp3UnJmLVISmlc57BgKUzdjr0lOtjqTZicL3PaYy6cU= 358 | github.com/jdkato/prose v1.2.1/go.mod h1:AiRHgVagnEx2JbQRQowVBKjG0bcs/vtkGCH1dYAL1rA= 359 | github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= 360 | github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= 361 | github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= 362 | github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= 363 | github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= 364 | github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= 365 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 366 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 367 | github.com/jjti/go-spancheck v0.6.4 h1:Tl7gQpYf4/TMU7AT84MN83/6PutY21Nb9fuQjFTpRRc= 368 | github.com/jjti/go-spancheck v0.6.4/go.mod h1:yAEYdKJ2lRkDA8g7X+oKUHXOWVAXSBJRv04OhF+QUjk= 369 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 370 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 371 | github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ= 372 | github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY= 373 | github.com/karamaru-alpha/copyloopvar v1.2.1 h1:wmZaZYIjnJ0b5UoKDjUHrikcV0zuPyyxI4SVplLd2CI= 374 | github.com/karamaru-alpha/copyloopvar v1.2.1/go.mod h1:nFmMlFNlClC2BPvNaHMdkirmTJxVCY0lhxBtlfOypMM= 375 | github.com/kisielk/errcheck v1.9.0 h1:9xt1zI9EBfcYBvdU1nVrzMzzUPUtPKs9bVSIM3TAb3M= 376 | github.com/kisielk/errcheck v1.9.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8= 377 | github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE= 378 | github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= 379 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 380 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 381 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 382 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 383 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 384 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 385 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 386 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 387 | github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= 388 | github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= 389 | github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs= 390 | github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= 391 | github.com/kyokomi/emoji/v2 v2.2.13 h1:GhTfQa67venUUvmleTNFnb+bi7S3aocF7ZCXU9fSO7U= 392 | github.com/kyokomi/emoji/v2 v2.2.13/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE= 393 | github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4= 394 | github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= 395 | github.com/ldez/exptostd v0.4.2 h1:l5pOzHBz8mFOlbcifTxzfyYbgEmoUqjxLFHZkjlbHXs= 396 | github.com/ldez/exptostd v0.4.2/go.mod h1:iZBRYaUmcW5jwCR3KROEZ1KivQQp6PHXbDPk9hqJKCQ= 397 | github.com/ldez/gomoddirectives v0.6.1 h1:Z+PxGAY+217f/bSGjNZr/b2KTXcyYLgiWI6geMBN2Qc= 398 | github.com/ldez/gomoddirectives v0.6.1/go.mod h1:cVBiu3AHR9V31em9u2kwfMKD43ayN5/XDgr+cdaFaKs= 399 | github.com/ldez/grignotin v0.9.0 h1:MgOEmjZIVNn6p5wPaGp/0OKWyvq42KnzAt/DAb8O4Ow= 400 | github.com/ldez/grignotin v0.9.0/go.mod h1:uaVTr0SoZ1KBii33c47O1M8Jp3OP3YDwhZCmzT9GHEk= 401 | github.com/ldez/tagliatelle v0.7.1 h1:bTgKjjc2sQcsgPiT902+aadvMjCeMHrY7ly2XKFORIk= 402 | github.com/ldez/tagliatelle v0.7.1/go.mod h1:3zjxUpsNB2aEZScWiZTHrAXOl1x25t3cRmzfK1mlo2I= 403 | github.com/ldez/usetesting v0.4.2 h1:J2WwbrFGk3wx4cZwSMiCQQ00kjGR0+tuuyW0Lqm4lwA= 404 | github.com/ldez/usetesting v0.4.2/go.mod h1:eEs46T3PpQ+9RgN9VjpY6qWdiw2/QmfiDeWmdZdrjIQ= 405 | github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= 406 | github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= 407 | github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk= 408 | github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I= 409 | github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= 410 | github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 411 | github.com/makeworld-the-better-one/dither/v2 v2.4.0 h1:Az/dYXiTcwcRSe59Hzw4RI1rSnAZns+1msaCXetrMFE= 412 | github.com/makeworld-the-better-one/dither/v2 v2.4.0/go.mod h1:VBtN8DXO7SNtyGmLiGA7IsFeKrBkQPze1/iAeM95arc= 413 | github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= 414 | github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= 415 | github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= 416 | github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= 417 | github.com/marekm4/color-extractor v1.2.1 h1:3Zb2tQsn6bITZ8MBVhc33Qn1k5/SEuZ18mrXGUqIwn0= 418 | github.com/marekm4/color-extractor v1.2.1/go.mod h1:90VjmiHI6M8ez9eYUaXLdcKnS+BAOp7w+NpwBdkJmpA= 419 | github.com/matoous/godox v1.1.0 h1:W5mqwbyWrwZv6OQ5Z1a/DHGMOvXYCBP3+Ht7KMoJhq4= 420 | github.com/matoous/godox v1.1.0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs= 421 | github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= 422 | github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= 423 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 424 | github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 425 | github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 426 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 427 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 428 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 429 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 430 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 431 | github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 432 | github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 433 | github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= 434 | github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= 435 | github.com/mgechev/revive v1.7.0 h1:JyeQ4yO5K8aZhIKf5rec56u0376h8AlKNQEmjfkjKlY= 436 | github.com/mgechev/revive v1.7.0/go.mod h1:qZnwcNhoguE58dfi96IJeSTPeZQejNeoMQLUZGi4SW4= 437 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 438 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 439 | github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE= 440 | github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 441 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= 442 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= 443 | github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= 444 | github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= 445 | github.com/muesli/smartcrop v0.3.0 h1:JTlSkmxWg/oQ1TcLDoypuirdE8Y/jzNirQeLkxpA6Oc= 446 | github.com/muesli/smartcrop v0.3.0/go.mod h1:i2fCI/UorTfgEpPPLWiFBv4pye+YAG78RwcQLUkocpI= 447 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= 448 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 449 | github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= 450 | github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= 451 | github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= 452 | github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= 453 | github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek= 454 | github.com/niklasfasching/go-org v1.7.0/go.mod h1:WuVm4d45oePiE0eX25GqTDQIt/qPW1T9DGkRscqLW5o= 455 | github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg= 456 | github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= 457 | github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= 458 | github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= 459 | github.com/nunnatsa/ginkgolinter v0.19.1 h1:mjwbOlDQxZi9Cal+KfbEJTCz327OLNfwNvoZ70NJ+c4= 460 | github.com/nunnatsa/ginkgolinter v0.19.1/go.mod h1:jkQ3naZDmxaZMXPWaS9rblH+i+GWXQCaS/JFIWcOH2s= 461 | github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= 462 | github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= 463 | github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= 464 | github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= 465 | github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU= 466 | github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= 467 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 468 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 469 | github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= 470 | github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= 471 | github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= 472 | github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= 473 | github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= 474 | github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= 475 | github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= 476 | github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= 477 | github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= 478 | github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= 479 | github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= 480 | github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= 481 | github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= 482 | github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= 483 | github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= 484 | github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 485 | github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= 486 | github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= 487 | github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= 488 | github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= 489 | github.com/pganalyze/pg_query_go/v6 v6.1.0 h1:jG5ZLhcVgL1FAw4C/0VNQaVmX1SUJx71wBGdtTtBvls= 490 | github.com/pganalyze/pg_query_go/v6 v6.1.0/go.mod h1:nvTHIuoud6e1SfrUaFwHqT0i4b5Nr+1rPWVds3B5+50= 491 | github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= 492 | github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb h1:3pSi4EDG6hg0orE1ndHkXvX6Qdq2cZn8gAPir8ymKZk= 493 | github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg= 494 | github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 h1:tdMsjOqUR7YXHoBitzdebTvOjs/swniBTOLy5XiMtuE= 495 | github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86/go.mod h1:exzhVYca3WRtd6gclGNErRWb1qEgff3LYta0LvRmON4= 496 | github.com/pingcap/log v1.1.0 h1:ELiPxACz7vdo1qAvvaWJg1NrYFoY6gqAh/+Uo6aXdD8= 497 | github.com/pingcap/log v1.1.0/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4= 498 | github.com/pingcap/tidb/pkg/parser v0.0.0-20250324122243-d51e00e5bbf0 h1:W3rpAI3bubR6VWOcwxDIG0Gz9G5rl5b3SL116T0vBt0= 499 | github.com/pingcap/tidb/pkg/parser v0.0.0-20250324122243-d51e00e5bbf0/go.mod h1:+8feuexTKcXHZF/dkDfvCwEyBAmgb4paFc3/WeYV2eE= 500 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 501 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 502 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 503 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 504 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 505 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 506 | github.com/polyfloyd/go-errorlint v1.7.1 h1:RyLVXIbosq1gBdk/pChWA8zWYLsq9UEw7a1L5TVMCnA= 507 | github.com/polyfloyd/go-errorlint v1.7.1/go.mod h1:aXjNb1x2TNhoLsk26iv1yl7a+zTnXPhwEMtEXukiLR8= 508 | github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= 509 | github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= 510 | github.com/pressly/goose/v3 v3.24.3 h1:DSWWNwwggVUsYZ0X2VitiAa9sKuqtBfe+Jr9zFGwWlM= 511 | github.com/pressly/goose/v3 v3.24.3/go.mod h1:v9zYL4xdViLHCUUJh/mhjnm6JrK7Eul8AS93IxiZM4E= 512 | github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= 513 | github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= 514 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 515 | github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= 516 | github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= 517 | github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= 518 | github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= 519 | github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= 520 | github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= 521 | github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo= 522 | github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI= 523 | github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= 524 | github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= 525 | github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= 526 | github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= 527 | github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= 528 | github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= 529 | github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= 530 | github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= 531 | github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= 532 | github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= 533 | github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI= 534 | github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= 535 | github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI= 536 | github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= 537 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= 538 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 539 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 540 | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 541 | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 542 | github.com/riza-io/grpc-go v0.2.0 h1:2HxQKFVE7VuYstcJ8zqpN84VnAoJ4dCL6YFhJewNcHQ= 543 | github.com/riza-io/grpc-go v0.2.0/go.mod h1:2bDvR9KkKC3KhtlSHfR3dAXjUMT86kg4UfWFyVGWqi8= 544 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 545 | github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= 546 | github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 547 | github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 548 | github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= 549 | github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= 550 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 551 | github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU= 552 | github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE= 553 | github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= 554 | github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= 555 | github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= 556 | github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= 557 | github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0= 558 | github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4= 559 | github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw= 560 | github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= 561 | github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= 562 | github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= 563 | github.com/sashamelentyev/usestdlibvars v1.28.0 h1:jZnudE2zKCtYlGzLVreNp5pmCdOxXUzwsMDBkR21cyQ= 564 | github.com/sashamelentyev/usestdlibvars v1.28.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= 565 | github.com/securego/gosec/v2 v2.22.2 h1:IXbuI7cJninj0nRpZSLCUlotsj8jGusohfONMrHoF6g= 566 | github.com/securego/gosec/v2 v2.22.2/go.mod h1:UEBGA+dSKb+VqM6TdehR7lnQtIIMorYJ4/9CW1KVQBE= 567 | github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= 568 | github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 569 | github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= 570 | github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= 571 | github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= 572 | github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= 573 | github.com/sirkon/dst v0.26.4 h1:ETxfjyp5JKE8OCpdybyyhzTyQqq/MwbIIcs7kxcUAcA= 574 | github.com/sirkon/dst v0.26.4/go.mod h1:e6HRc56jU5F2XT6GB8Cyci1Jb5cjX6gLqrm5+T/P7Zo= 575 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 576 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 577 | github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= 578 | github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= 579 | github.com/sivchari/tenv v1.12.1 h1:+E0QzjktdnExv/wwsnnyk4oqZBUfuh89YMQT1cyuvSY= 580 | github.com/sivchari/tenv v1.12.1/go.mod h1:1LjSOUCc25snIr5n3DtGGrENhX3LuWefcplwVGC24mw= 581 | github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM= 582 | github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c= 583 | github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= 584 | github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= 585 | github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= 586 | github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= 587 | github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= 588 | github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= 589 | github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= 590 | github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= 591 | github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= 592 | github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= 593 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 594 | github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= 595 | github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 596 | github.com/spf13/viper v1.20.0 h1:zrxIyR3RQIOsarIrgL8+sAvALXul9jeEPa06Y0Ph6vY= 597 | github.com/spf13/viper v1.20.0/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= 598 | github.com/sqlc-dev/sqlc v1.29.0 h1:HQctoD7y/i29Bao53qXO7CZ/BV9NcvpGpsJWvz9nKWs= 599 | github.com/sqlc-dev/sqlc v1.29.0/go.mod h1:BavmYw11px5AdPOjAVHmb9fctP5A8GTziC38wBF9tp0= 600 | github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= 601 | github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= 602 | github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8Bg8etvARQ1rpyl4= 603 | github.com/stbenjam/no-sprintf-host-port v0.2.0/go.mod h1:eL0bQ9PasS0hsyTyfTjjG+E80QIyPnBVQbYZyv20Jfk= 604 | github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= 605 | github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= 606 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 607 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 608 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 609 | github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= 610 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 611 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 612 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 613 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 614 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 615 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 616 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 617 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 618 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 619 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 620 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 621 | github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= 622 | github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= 623 | github.com/tdakkota/asciicheck v0.4.1 h1:bm0tbcmi0jezRA2b5kg4ozmMuGAFotKI3RZfrhfovg8= 624 | github.com/tdakkota/asciicheck v0.4.1/go.mod h1:0k7M3rCfRXb0Z6bwgvkEIMleKH3kXNz9UqJ9Xuqopr8= 625 | github.com/tdewolff/minify/v2 v2.20.37 h1:Q97cx4STXCh1dlWDlNHZniE8BJ2EBL0+2b0n92BJQhw= 626 | github.com/tdewolff/minify/v2 v2.20.37/go.mod h1:L1VYef/jwKw6Wwyk5A+T0mBjjn3mMPgmjjA688RNsxU= 627 | github.com/tdewolff/parse/v2 v2.7.15 h1:hysDXtdGZIRF5UZXwpfn3ZWRbm+ru4l53/ajBRGpCTw= 628 | github.com/tdewolff/parse/v2 v2.7.15/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= 629 | github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= 630 | github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo= 631 | github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= 632 | github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= 633 | github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= 634 | github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= 635 | github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= 636 | github.com/tetafro/godot v1.5.0 h1:aNwfVI4I3+gdxjMgYPus9eHmoBeJIbnajOyqZYStzuw= 637 | github.com/tetafro/godot v1.5.0/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= 638 | github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I= 639 | github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM= 640 | github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 h1:y4mJRFlM6fUyPhoXuFg/Yu02fg/nIPFMOY8tOqppoFg= 641 | github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= 642 | github.com/timonwong/loggercheck v0.10.1 h1:uVZYClxQFpw55eh+PIoqM7uAOHMrhVcDoWDery9R8Lg= 643 | github.com/timonwong/loggercheck v0.10.1/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= 644 | github.com/tomarrell/wrapcheck/v2 v2.10.0 h1:SzRCryzy4IrAH7bVGG4cK40tNUhmVmMDuJujy4XwYDg= 645 | github.com/tomarrell/wrapcheck/v2 v2.10.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= 646 | github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= 647 | github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= 648 | github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= 649 | github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= 650 | github.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI= 651 | github.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA= 652 | github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSWoFa+g= 653 | github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= 654 | github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYRA= 655 | github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU= 656 | github.com/uudashr/iface v1.3.1 h1:bA51vmVx1UIhiIsQFSNq6GZ6VPTk3WNMZgRiCe9R29U= 657 | github.com/uudashr/iface v1.3.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg= 658 | github.com/vektra/mockery/v2 v2.53.3 h1:yBU8XrzntcZdcNRRv+At0anXgSaFtgkyVUNm3f4an3U= 659 | github.com/vektra/mockery/v2 v2.53.3/go.mod h1:hIFFb3CvzPdDJJiU7J4zLRblUMv7OuezWsHPmswriwo= 660 | github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07 h1:mJdDDPblDfPe7z7go8Dvv1AJQDI3eQ/5xith3q2mFlo= 661 | github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07/go.mod h1:Ak17IJ037caFp4jpCw/iQQ7/W74Sqpb1YuKJU6HTKfM= 662 | github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 h1:OvLBa8SqJnZ6P+mjlzc2K7PM22rRUPE1x32G9DTPrC4= 663 | github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52/go.mod h1:jMeV4Vpbi8osrE/pKUxRZkVaA0EX7NZN0A9/oRzgpgY= 664 | github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU= 665 | github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg= 666 | github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= 667 | github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= 668 | github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs= 669 | github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4= 670 | github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw= 671 | github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= 672 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 673 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 674 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 675 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 676 | github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 677 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 678 | github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= 679 | github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= 680 | github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4= 681 | github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= 682 | github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= 683 | github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= 684 | gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= 685 | gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= 686 | go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= 687 | go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= 688 | go-simpler.org/musttag v0.13.0 h1:Q/YAW0AHvaoaIbsPj3bvEI5/QFP7w696IMUpnKXQfCE= 689 | go-simpler.org/musttag v0.13.0/go.mod h1:FTzIGeK6OkKlUDVpj0iQUXZLUO1Js9+mvykDQy9C5yM= 690 | go-simpler.org/sloglint v0.9.0 h1:/40NQtjRx9txvsB/RN022KsUJU+zaaSb/9q9BSefSrE= 691 | go-simpler.org/sloglint v0.9.0/go.mod h1:G/OrAF6uxj48sHahCzrbarVMptL2kjWTaUeC8+fOGww= 692 | go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= 693 | go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= 694 | go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= 695 | go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= 696 | go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= 697 | go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= 698 | go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= 699 | go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= 700 | go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= 701 | go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= 702 | go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= 703 | go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= 704 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 705 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 706 | go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 707 | go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= 708 | go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= 709 | go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= 710 | go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= 711 | go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= 712 | go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= 713 | go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= 714 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 715 | go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= 716 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 717 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 718 | go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= 719 | go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= 720 | go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 721 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 722 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 723 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 724 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 725 | golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= 726 | golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 727 | golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= 728 | golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= 729 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 730 | golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= 731 | golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= 732 | golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= 733 | golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= 734 | golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac h1:TSSpLIG4v+p0rPv1pNOQtl1I8knsO4S9trOxNMOLVP4= 735 | golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= 736 | golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw= 737 | golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM= 738 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 739 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 740 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 741 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 742 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 743 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 744 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 745 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 746 | golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= 747 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 748 | golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 749 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 750 | golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 751 | golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 752 | golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 753 | golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= 754 | golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= 755 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 756 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 757 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 758 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 759 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 760 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 761 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 762 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 763 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 764 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 765 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 766 | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 767 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 768 | golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= 769 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 770 | golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 771 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 772 | golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 773 | golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 774 | golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= 775 | golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= 776 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 777 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 778 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 779 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 780 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 781 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 782 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 783 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 784 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 785 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 786 | golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 787 | golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 788 | golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= 789 | golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 790 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 791 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 792 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 793 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 794 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 795 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 796 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 797 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 798 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 799 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 800 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 801 | golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 802 | golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 803 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 804 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 805 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 806 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 807 | golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 808 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 809 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 810 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 811 | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 812 | golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 813 | golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= 814 | golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 815 | golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 h1:FemxDzfMUcK2f3YY4H+05K9CDzbSVr2+q/JKN45pey0= 816 | golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= 817 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 818 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 819 | golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= 820 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 821 | golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= 822 | golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= 823 | golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= 824 | golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= 825 | golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= 826 | golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= 827 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 828 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 829 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 830 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 831 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 832 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 833 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 834 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 835 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 836 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 837 | golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= 838 | golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= 839 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 840 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 841 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 842 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 843 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 844 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 845 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 846 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 847 | golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 848 | golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 849 | golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 850 | golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 851 | golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 852 | golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= 853 | golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= 854 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 855 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 856 | golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= 857 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 858 | golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= 859 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 860 | golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= 861 | golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= 862 | golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 863 | golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= 864 | golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= 865 | golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I= 866 | golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s= 867 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 868 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 869 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 870 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 871 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 872 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 873 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 874 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 875 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 876 | google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0= 877 | google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU= 878 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA= 879 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= 880 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 881 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 882 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 883 | google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= 884 | google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= 885 | google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A= 886 | google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA= 887 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 888 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 889 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 890 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 891 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 892 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 893 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 894 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 895 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 896 | google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 897 | google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= 898 | google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 899 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 900 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 901 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 902 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 903 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 904 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 905 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= 906 | gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= 907 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 908 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 909 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 910 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 911 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 912 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 913 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 914 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 915 | gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= 916 | gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= 917 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 918 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 919 | honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI= 920 | honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= 921 | modernc.org/cc/v4 v4.26.0 h1:QMYvbVduUGH0rrO+5mqF/PSPPRZNpRtg2CLELy7vUpA= 922 | modernc.org/cc/v4 v4.26.0/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= 923 | modernc.org/ccgo/v4 v4.26.0 h1:gVzXaDzGeBYJ2uXTOpR8FR7OlksDOe9jxnjhIKCsiTc= 924 | modernc.org/ccgo/v4 v4.26.0/go.mod h1:Sem8f7TFUtVXkG2fiaChQtyyfkqhJBg/zjEJBkmuAVY= 925 | modernc.org/fileutil v1.3.1 h1:8vq5fe7jdtEvoCf3Zf9Nm0Q05sH6kGx0Op2CPx1wTC8= 926 | modernc.org/fileutil v1.3.1/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= 927 | modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= 928 | modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= 929 | modernc.org/libc v1.65.0 h1:e183gLDnAp9VJh6gWKdTy0CThL9Pt7MfcR/0bgb7Y1Y= 930 | modernc.org/libc v1.65.0/go.mod h1:7m9VzGq7APssBTydds2zBcxGREwvIGpuUBaKTXdm2Qs= 931 | modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= 932 | modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= 933 | modernc.org/memory v1.10.0 h1:fzumd51yQ1DxcOxSO+S6X7+QTuVU+n8/Aj7swYjFfC4= 934 | modernc.org/memory v1.10.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= 935 | modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= 936 | modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= 937 | modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= 938 | modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= 939 | modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI= 940 | modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM= 941 | modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= 942 | modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= 943 | modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= 944 | modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= 945 | mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU= 946 | mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo= 947 | mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U= 948 | mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ= 949 | -------------------------------------------------------------------------------- /ops/deployment/fly.toml: -------------------------------------------------------------------------------- 1 | # fly.toml app configuration file generated for go-service on 2024-10-06T12:32:31+03:00 2 | # 3 | # See https://fly.io/docs/reference/configuration/ for information about how to use this file. 4 | # 5 | 6 | app = "go-service" 7 | 8 | [build] 9 | build-target = "runner" 10 | dockerfile = "Dockerfile" 11 | 12 | [build.args] 13 | MODE = "production" 14 | 15 | [deploy] 16 | # max_unavailable = 1 17 | strategy = "rolling" 18 | 19 | [env] 20 | APP_ENV = "production" 21 | 22 | [http_service] 23 | auto_start_machines = true 24 | auto_stop_machines = true 25 | force_https = true 26 | internal_port = 3_000 27 | min_machines_running = 0 28 | processes = [ "app" ] 29 | 30 | [[vm]] 31 | cpu_kind = "shared" 32 | cpus = 1 33 | memory = "1gb" 34 | -------------------------------------------------------------------------------- /ops/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # versions 2 | 3 | FROM golang:1-bookworm AS upstream-builder 4 | FROM gcr.io/distroless/base-debian12 AS upstream-runner 5 | 6 | # Create a minimal image base-debian12 or static-debian12 7 | # (see: https://github.com/GoogleContainerTools/distroless#why-should-i-use-distroless-images) 8 | 9 | # ------------------ 10 | # builder-base image 11 | # ------------------ 12 | FROM upstream-builder AS builder-base 13 | 14 | # Install the Protocol Buffers Library and Compiler 15 | RUN apt-get update && apt-get -y install --no-install-recommends \ 16 | libprotobuf-dev \ 17 | protobuf-compiler 18 | 19 | # Configuration 20 | ARG GH_LOGIN 21 | ENV GH_LOGIN=$GH_USER 22 | 23 | ARG GH_ACCESS_TOKEN 24 | ENV GH_ACCESS_TOKEN=$GH_ACCESS_TOKEN 25 | 26 | ARG GH_PATH 27 | ENV GH_PATH=$GH_PATH 28 | 29 | # Setup for private Go Modules where available 30 | RUN echo "machine github.com login ${GH_LOGIN} password ${GH_ACCESS_TOKEN}" > ~/.netrc 31 | ENV GOPRIVATE "${GH_PATH}/*" 32 | RUN go env -w GOPRIVATE="${GH_PATH}/*" 33 | ENV GO111MODULE=on 34 | ENV CGO_ENABLED=0 35 | ENV GOOS=linux 36 | 37 | # Set working directory 38 | # RUN mkdir -p /app 39 | WORKDIR /app 40 | 41 | # Install dependencies first to improve caching 42 | COPY ./go.mod ./go.sum ./ 43 | RUN go mod download && go mod verify 44 | 45 | # Build the application 46 | COPY . . 47 | 48 | # ------------------------ 49 | # runner-development image 50 | # ------------------------ 51 | 52 | FROM builder-base AS runner-development 53 | 54 | EXPOSE 8080 55 | ENTRYPOINT ["go", "run", "./cmd/serve/"] 56 | 57 | # ------------------------ 58 | # builder-production image 59 | # ------------------------ 60 | 61 | FROM builder-base AS builder-production 62 | 63 | RUN go build ./cmd/serve/ 64 | 65 | # ----------------------- 66 | # runner-production image 67 | # ----------------------- 68 | FROM upstream-runner AS runner-production 69 | 70 | # Copy the binary from the builder-production container 71 | COPY --from=builder-production --chown=nonroot:nonroot /app/serve / 72 | # COPY --from=builder-production /bin/sh /bin/sh 73 | # COPY --from=builder-production /bin/cat /bin/cat 74 | 75 | # Run as a non-root user 76 | USER nonroot 77 | 78 | EXPOSE 8080 79 | ENTRYPOINT ["/serve"] 80 | -------------------------------------------------------------------------------- /ops/docker/compose.production.yml: -------------------------------------------------------------------------------- 1 | name: production 2 | 3 | services: 4 | sample: 5 | tty: true 6 | stdin_open: true 7 | restart: unless-stopped 8 | build: 9 | context: ../../ 10 | dockerfile: ./ops/docker/Dockerfile 11 | target: runner-production 12 | environment: 13 | PORT: 8080 14 | DATA__SOURCES__DEFAULT__DSN: postgres://postgres:s3cr3t@postgres:5432/postgres?sslmode=disable 15 | LOG__PRETTY: false 16 | networks: 17 | - acik-io-network 18 | ports: 19 | - 8080:8080 20 | depends_on: 21 | - postgres 22 | 23 | postgres: 24 | image: postgres:16-bookworm 25 | restart: unless-stopped 26 | environment: 27 | POSTGRES_PASSWORD: s3cr3t 28 | healthcheck: 29 | test: ["CMD-SHELL", "psql -U 'postgres' -c '\\q'"] 30 | interval: 10s 31 | timeout: 5s 32 | retries: 10 33 | volumes: 34 | - ./resources/init.sql:/docker-entrypoint-initdb.d/init.sql 35 | networks: 36 | - acik-io-network 37 | ports: 38 | - 5435:5432 39 | 40 | networks: 41 | acik-io-network: 42 | driver: bridge 43 | -------------------------------------------------------------------------------- /ops/docker/compose.yml: -------------------------------------------------------------------------------- 1 | name: development 2 | 3 | services: 4 | sample: 5 | tty: true 6 | stdin_open: true 7 | restart: unless-stopped 8 | build: 9 | context: ../../ 10 | dockerfile: ./ops/docker/Dockerfile 11 | target: runner-development 12 | develop: 13 | watch: 14 | - action: sync+restart 15 | path: ../ 16 | target: /app/ 17 | ignore: 18 | - .* 19 | - tmp/ 20 | environment: 21 | PORT: 8080 22 | DATA__SOURCES__DEFAULT__DSN: postgres://postgres:s3cr3t@postgres:5432/postgres?sslmode=disable 23 | LOG__LEVEL: DEBUG 24 | LOG__PRETTY: false 25 | networks: 26 | - acik-io-network 27 | ports: 28 | - 8080:8080 29 | depends_on: 30 | fluentd: 31 | condition: service_healthy 32 | postgres: 33 | condition: service_healthy 34 | logging: 35 | driver: fluentd 36 | options: 37 | fluentd-address: localhost:24224 38 | fluentd-async-connect: "true" 39 | tag: sample 40 | 41 | postgres: 42 | image: postgres:16-bookworm 43 | restart: unless-stopped 44 | environment: 45 | POSTGRES_PASSWORD: s3cr3t 46 | healthcheck: 47 | test: ["CMD-SHELL", "psql -U 'postgres' -c '\\q'"] 48 | interval: 10s 49 | timeout: 5s 50 | retries: 10 51 | volumes: 52 | - postgres-data:/var/lib/postgresql/data 53 | - ./resources/init.sql:/docker-entrypoint-initdb.d/init.sql 54 | networks: 55 | - acik-io-network 56 | ports: 57 | - 5432:5432 58 | depends_on: 59 | fluentd: 60 | condition: service_healthy 61 | logging: 62 | driver: fluentd 63 | options: 64 | fluentd-address: localhost:24224 65 | fluentd-async-connect: "true" 66 | tag: postgres 67 | 68 | prometheus: 69 | image: prom/prometheus:latest 70 | configs: 71 | - source: prometheus-config 72 | target: /etc/prometheus/prometheus.yml 73 | networks: 74 | - acik-io-network 75 | ports: 76 | - 9090:9090 77 | 78 | fluentd: 79 | build: 80 | context: ./resources/fluentd/ 81 | environment: 82 | FLUENTD_CONF: "fluent.conf" 83 | configs: 84 | - source: fluentd-config 85 | target: /fluentd/etc/fluent.conf 86 | healthcheck: 87 | test: ["CMD", "nc", "-z", "localhost", "24224"] 88 | interval: 10s 89 | retries: 5 90 | timeout: 5s 91 | volumes: 92 | # - host_logs:/var/log 93 | # Needed for journald log ingestion: 94 | - /etc/machine-id:/etc/machine-id 95 | - /dev/log:/dev/log 96 | - /var/run/systemd/journal/:/var/run/systemd/journal/ 97 | networks: 98 | - acik-io-network 99 | ports: 100 | - 24224:24224 101 | - 24224:24224/udp 102 | depends_on: 103 | loki: 104 | condition: service_started 105 | logging: 106 | options: 107 | tag: infra.monitoring 108 | 109 | loki: 110 | image: grafana/loki:main 111 | user: "0" 112 | configs: 113 | - source: loki-config 114 | target: /etc/loki/local_config.yaml 115 | volumes: 116 | - loki-data:/var/loki 117 | command: -config.file=/etc/loki/local_config.yaml 118 | networks: 119 | - acik-io-network 120 | ports: 121 | - 3100:3100 122 | 123 | grafana: 124 | image: grafana/grafana:main 125 | environment: 126 | GF_SECURITY_ADMIN_USER: admin 127 | GF_SECURITY_ADMIN_PASSWORD: admin 128 | GF_AUTH_ANONYMOUS_ENABLED: true 129 | GF_AUTH_ANONYMOUS_ORG_ROLE: Viewer 130 | volumes: 131 | # - grafana-data:/var/lib/grafana 132 | - ./resources/grafana/provisioning:/etc/grafana/provisioning 133 | - ./resources/grafana/dashboards:/var/lib/grafana/dashboards 134 | networks: 135 | - acik-io-network 136 | ports: 137 | - 3000:3000 138 | 139 | configs: 140 | prometheus-config: 141 | file: ./resources/prometheus/prometheus.yml 142 | fluentd-config: 143 | file: ./resources/fluentd/fluentd.conf 144 | loki-config: 145 | file: ./resources/loki/local_config.yaml 146 | 147 | volumes: 148 | postgres-data: 149 | # grafana-data: 150 | loki-data: 151 | 152 | networks: 153 | acik-io-network: 154 | driver: bridge 155 | -------------------------------------------------------------------------------- /ops/docker/resources/fluentd/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fluent/fluentd:edge-debian 2 | 3 | USER root 4 | 5 | RUN apt-get update && apt-get install -y netcat-openbsd 6 | RUN gem install fluent-plugin-grafana-loki 7 | 8 | USER fluent 9 | -------------------------------------------------------------------------------- /ops/docker/resources/fluentd/fluentd.conf: -------------------------------------------------------------------------------- 1 | 2 | @type forward 3 | port 24224 4 | 5 | 6 | 7 | @type parser 8 | key_name log 9 | 10 | @type json 11 | 12 | 13 | 14 | 15 | @type loki 16 | url http://loki:3100 17 | # url http://loki:3100/loki/api/v1/push 18 | # insecure_tls true 19 | # tenant ${$.kubernetes.labels.tenant} 20 | 21 | extra_labels {"agent":"fluentd"} 22 | # extract_kubernetes_labels true 23 | # remove_keys kubernetes 24 | # 25 | # @type json 26 | # 27 | 28 | 33 | 34 | 35 | chunk_limit_size 1m 36 | flush_interval 10s 37 | flush_at_shutdown true 38 | 39 | 40 | 41 | 46 | -------------------------------------------------------------------------------- /ops/docker/resources/grafana/dashboards/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": { 7 | "type": "grafana", 8 | "uid": "-- Grafana --" 9 | }, 10 | "enable": true, 11 | "hide": true, 12 | "iconColor": "rgba(0, 211, 255, 1)", 13 | "name": "Annotations & Alerts", 14 | "type": "dashboard" 15 | } 16 | ] 17 | }, 18 | "editable": true, 19 | "fiscalYearStartMonth": 0, 20 | "graphTooltip": 0, 21 | "id": 1, 22 | "links": [], 23 | "panels": [ 24 | { 25 | "datasource": { 26 | "default": true, 27 | "type": "loki", 28 | "uid": "P8E80F9AEF21F6940" 29 | }, 30 | "gridPos": { 31 | "h": 20, 32 | "w": 24, 33 | "x": 0, 34 | "y": 0 35 | }, 36 | "id": 1, 37 | "options": { 38 | "dedupStrategy": "none", 39 | "enableLogDetails": true, 40 | "prettifyLogMessage": true, 41 | "showCommonLabels": false, 42 | "showLabels": false, 43 | "showTime": true, 44 | "sortOrder": "Descending", 45 | "wrapLogMessage": false 46 | }, 47 | "targets": [ 48 | { 49 | "datasource": { 50 | "type": "loki", 51 | "uid": "P8E80F9AEF21F6940" 52 | }, 53 | "editorMode": "code", 54 | "expr": "{env=\"dev\"}", 55 | "queryType": "range", 56 | "refId": "A" 57 | } 58 | ], 59 | "title": "Logs", 60 | "type": "logs" 61 | } 62 | ], 63 | "schemaVersion": 39, 64 | "tags": [], 65 | "templating": { 66 | "list": [] 67 | }, 68 | "time": { 69 | "from": "now-6h", 70 | "to": "now" 71 | }, 72 | "timepicker": {}, 73 | "timezone": "browser", 74 | "title": "Main", 75 | "uid": "edyijnx7hpqm8d", 76 | "version": 2, 77 | "weekStart": "" 78 | } 79 | -------------------------------------------------------------------------------- /ops/docker/resources/grafana/provisioning/dashboards/dashboards.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: "Dashboard Provider" 5 | orgId: 1 6 | type: file 7 | disableDeletion: false 8 | editable: true 9 | updateIntervalSeconds: 10 10 | allowUiUpdates: false 11 | options: 12 | path: /var/lib/grafana/dashboards 13 | foldersFromFilesStructure: true 14 | -------------------------------------------------------------------------------- /ops/docker/resources/grafana/provisioning/datasources/loki.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Loki 5 | type: loki 6 | access: proxy 7 | url: http://loki:3100 8 | isDefault: true 9 | jsonData: 10 | maxLines: 1000 11 | -------------------------------------------------------------------------------- /ops/docker/resources/grafana/provisioning/datasources/prometheus.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Prometheus 5 | type: prometheus 6 | access: proxy 7 | url: http://prometheus:9090 8 | -------------------------------------------------------------------------------- /ops/docker/resources/loki/local_config.yaml: -------------------------------------------------------------------------------- 1 | auth_enabled: false 2 | 3 | server: 4 | http_listen_port: 3100 5 | grpc_listen_port: 9095 6 | 7 | common: 8 | path_prefix: /var/loki 9 | storage: 10 | filesystem: 11 | chunks_directory: /var/loki/chunks 12 | rules_directory: /var/loki/rules 13 | replication_factor: 1 14 | ring: 15 | kvstore: 16 | store: inmemory 17 | 18 | schema_config: 19 | configs: 20 | - from: 2020-10-24 21 | store: tsdb 22 | object_store: filesystem 23 | schema: v13 24 | index: 25 | prefix: index_ 26 | period: 24h 27 | 28 | compactor: 29 | working_directory: /var/loki/boltdb-shipper-compactor 30 | #shared_store: filesystem 31 | 32 | ruler: 33 | storage: 34 | type: local 35 | rule_path: /tmp/loki/rules-temp 36 | alertmanager_url: http://localhost:9093 37 | -------------------------------------------------------------------------------- /ops/docker/resources/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | 4 | scrape_configs: 5 | - job_name: "prometheus" 6 | static_configs: 7 | - targets: ["localhost:9090"] 8 | 9 | - job_name: "sample" 10 | static_configs: 11 | - targets: ["sample:8080"] 12 | -------------------------------------------------------------------------------- /ops/load_tests/definitions/broadcast.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "github.com/eser/go-service/pkg/proto-go/broadcast"; 4 | 5 | package broadcast; 6 | 7 | // CHANNELS 8 | 9 | message Channel { 10 | string id = 1; 11 | string name = 2; 12 | } 13 | 14 | message Channels { 15 | repeated Channel channels = 1; 16 | } 17 | 18 | message GetByIdRequest { 19 | optional string id = 1; 20 | } 21 | 22 | message ListRequest { 23 | } 24 | 25 | service ChannelService { 26 | rpc GetById(GetByIdRequest) returns (Channel) {} 27 | rpc List(ListRequest) returns (Channels) {} 28 | } 29 | 30 | // MESSAGES 31 | 32 | message Message { 33 | string body = 1; 34 | } 35 | 36 | message SendRequest { 37 | string channelId = 1; 38 | Message message = 2; 39 | } 40 | 41 | enum SendResultType { 42 | SUCCESS = 0; 43 | ERROR = 1; 44 | } 45 | 46 | message SendResponse { 47 | SendResultType result = 1; 48 | optional string error = 2; 49 | } 50 | 51 | service MessageService { 52 | rpc Send(SendRequest) returns (SendResponse) {} 53 | } 54 | -------------------------------------------------------------------------------- /ops/load_tests/go_grpc.js: -------------------------------------------------------------------------------- 1 | import grpc from "k6/net/grpc"; 2 | import exec from "k6/execution"; 3 | import { check } from "k6"; 4 | 5 | export const options = { 6 | // A number specifying the number of VUs to run concurrently. 7 | vus: 10, 8 | // A string specifying the total duration of the test run. 9 | duration: "20s", 10 | // The following section contains configuration options for execution of this 11 | // test script in Grafana Cloud. 12 | // 13 | // See https://grafana.com/docs/grafana-cloud/k6/get-started/run-cloud-tests-from-the-cli/ 14 | // to learn about authoring and running k6 test scripts in Grafana k6 Cloud. 15 | // 16 | // cloud: { 17 | // // The ID of the project to which the test is assigned in the k6 Cloud UI. 18 | // // By default tests are executed in default project. 19 | // projectID: "", 20 | // // The name of the test in the k6 Cloud UI. 21 | // // Test runs with the same name will be grouped. 22 | // name: "script.js" 23 | // }, 24 | 25 | // Uncomment this section to enable the use of Browser API in your tests. 26 | // 27 | // See https://grafana.com/docs/k6/latest/using-k6-browser/running-browser-tests/ to learn more 28 | // about using Browser API in your test scripts. 29 | // 30 | // scenarios: { 31 | // // The scenario name appears in the result summary, tags, and so on. 32 | // // You can give the scenario any name, as long as each name in the script is unique. 33 | // ui: { 34 | // // Executor is a mandatory parameter for browser-based tests. 35 | // // Shared iterations in this case tells k6 to reuse VUs to execute iterations. 36 | // // 37 | // // See https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/ for other executor types. 38 | // executor: 'shared-iterations', 39 | // options: { 40 | // browser: { 41 | // // This is a mandatory parameter that instructs k6 to launch and 42 | // // connect to a chromium-based browser, and use it to run UI-based 43 | // // tests. 44 | // type: 'chromium', 45 | // }, 46 | // }, 47 | // }, 48 | // } 49 | }; 50 | 51 | // The function that defines VU logic. 52 | // 53 | // See https://grafana.com/docs/k6/latest/examples/get-started-with-k6/ to learn more 54 | // about authoring k6 scripts. 55 | // 56 | 57 | const client = new grpc.Client(); 58 | client.load(["definitions"], "broadcast.proto"); 59 | 60 | export default function () { 61 | if (exec.vu.iterationInInstance == 0) { 62 | client.connect("localhost:9090", { plaintext: true }); 63 | } 64 | 65 | const data = { 66 | channelId: "1", 67 | message: { 68 | body: "test message", 69 | }, 70 | }; 71 | 72 | const response = client.invoke("broadcast.MessageService/Send", data); 73 | check(response, { 74 | "status is OK": (r) => r && r.status === grpc.StatusOK, 75 | }); 76 | 77 | //client.close() 78 | } 79 | -------------------------------------------------------------------------------- /ops/load_tests/go_http.js: -------------------------------------------------------------------------------- 1 | import http from "k6/http"; 2 | 3 | export const options = { 4 | // A number specifying the number of VUs to run concurrently. 5 | vus: 10, 6 | // A string specifying the total duration of the test run. 7 | duration: "20s", 8 | // The following section contains configuration options for execution of this 9 | // test script in Grafana Cloud. 10 | // 11 | // See https://grafana.com/docs/grafana-cloud/k6/get-started/run-cloud-tests-from-the-cli/ 12 | // to learn about authoring and running k6 test scripts in Grafana k6 Cloud. 13 | // 14 | // cloud: { 15 | // // The ID of the project to which the test is assigned in the k6 Cloud UI. 16 | // // By default tests are executed in default project. 17 | // projectID: "", 18 | // // The name of the test in the k6 Cloud UI. 19 | // // Test runs with the same name will be grouped. 20 | // name: "script.js" 21 | // }, 22 | 23 | // Uncomment this section to enable the use of Browser API in your tests. 24 | // 25 | // See https://grafana.com/docs/k6/latest/using-k6-browser/running-browser-tests/ to learn more 26 | // about using Browser API in your test scripts. 27 | // 28 | // scenarios: { 29 | // // The scenario name appears in the result summary, tags, and so on. 30 | // // You can give the scenario any name, as long as each name in the script is unique. 31 | // ui: { 32 | // // Executor is a mandatory parameter for browser-based tests. 33 | // // Shared iterations in this case tells k6 to reuse VUs to execute iterations. 34 | // // 35 | // // See https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/ for other executor types. 36 | // executor: 'shared-iterations', 37 | // options: { 38 | // browser: { 39 | // // This is a mandatory parameter that instructs k6 to launch and 40 | // // connect to a chromium-based browser, and use it to run UI-based 41 | // // tests. 42 | // type: 'chromium', 43 | // }, 44 | // }, 45 | // }, 46 | // } 47 | }; 48 | 49 | // The function that defines VU logic. 50 | // 51 | // See https://grafana.com/docs/k6/latest/examples/get-started-with-k6/ to learn more 52 | // about authoring k6 scripts. 53 | // 54 | export default function () { 55 | http.post( 56 | "http://localhost:8080/send", 57 | JSON.stringify({ 58 | channelId: "1", 59 | message: { 60 | body: "test message", 61 | }, 62 | }), 63 | { 64 | headers: { 65 | "Content-Type": "application/json", 66 | }, 67 | }, 68 | ); 69 | } 70 | -------------------------------------------------------------------------------- /pkg/sample/adapters/appcontext/appcontext.go: -------------------------------------------------------------------------------- 1 | package appcontext 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/eser/ajan/configfx" 10 | "github.com/eser/ajan/datafx" 11 | "github.com/eser/ajan/logfx" 12 | "github.com/eser/ajan/metricsfx" 13 | "github.com/eser/ajan/queuefx" 14 | ) 15 | 16 | var ErrInitFailed = errors.New("failed to initialize app context") 17 | 18 | type AppContext struct { 19 | Config *AppConfig 20 | Logger *logfx.Logger 21 | Metrics *metricsfx.MetricsProvider 22 | Data *datafx.Registry 23 | Queue *queuefx.Registry 24 | } 25 | 26 | func NewAppContext(ctx context.Context) (*AppContext, error) { 27 | appContext := &AppContext{} //nolint:exhaustruct 28 | 29 | // config 30 | cl := configfx.NewConfigManager() 31 | 32 | appContext.Config = &AppConfig{} //nolint:exhaustruct 33 | 34 | err := cl.LoadDefaults(appContext.Config) 35 | if err != nil { 36 | return nil, fmt.Errorf("%w: %w", ErrInitFailed, err) 37 | } 38 | 39 | // logger 40 | appContext.Logger, err = logfx.NewLoggerAsDefault(os.Stdout, &appContext.Config.Log) 41 | if err != nil { 42 | return nil, fmt.Errorf("%w: %w", ErrInitFailed, err) 43 | } 44 | 45 | // metrics 46 | appContext.Metrics = metricsfx.NewMetricsProvider() 47 | 48 | err = appContext.Metrics.RegisterNativeCollectors() 49 | if err != nil { 50 | return nil, fmt.Errorf("%w: %w", ErrInitFailed, err) 51 | } 52 | 53 | // data 54 | appContext.Data = datafx.NewRegistry(appContext.Logger) 55 | 56 | err = appContext.Data.LoadFromConfig(ctx, &appContext.Config.Data) 57 | if err != nil { 58 | return nil, fmt.Errorf("%w: %w", ErrInitFailed, err) 59 | } 60 | 61 | // queue 62 | appContext.Queue = queuefx.NewRegistry(appContext.Logger) 63 | 64 | err = appContext.Queue.LoadFromConfig(ctx, &appContext.Config.Queue) 65 | if err != nil { 66 | return nil, fmt.Errorf("%w: %w", ErrInitFailed, err) 67 | } 68 | 69 | return appContext, nil 70 | } 71 | -------------------------------------------------------------------------------- /pkg/sample/adapters/appcontext/config.go: -------------------------------------------------------------------------------- 1 | package appcontext 2 | 3 | import ( 4 | "github.com/eser/ajan" 5 | ) 6 | 7 | type FeatureFlags struct { 8 | Dummy bool `conf:"DUMMY" default:"false"` // dummy feature flag 9 | } 10 | 11 | type AppConfig struct { 12 | ajan.BaseConfig 13 | 14 | Features FeatureFlags `conf:"FEATURES"` 15 | } 16 | -------------------------------------------------------------------------------- /pkg/sample/adapters/grpc/generated/broadcast.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.35.1 4 | // protoc v5.27.1 5 | // source: broadcast/broadcast.proto 6 | 7 | package generated 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type SendResultType int32 24 | 25 | const ( 26 | SendResultType_SUCCESS SendResultType = 0 27 | SendResultType_ERROR SendResultType = 1 28 | ) 29 | 30 | // Enum value maps for SendResultType. 31 | var ( 32 | SendResultType_name = map[int32]string{ 33 | 0: "SUCCESS", 34 | 1: "ERROR", 35 | } 36 | SendResultType_value = map[string]int32{ 37 | "SUCCESS": 0, 38 | "ERROR": 1, 39 | } 40 | ) 41 | 42 | func (x SendResultType) Enum() *SendResultType { 43 | p := new(SendResultType) 44 | *p = x 45 | return p 46 | } 47 | 48 | func (x SendResultType) String() string { 49 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 50 | } 51 | 52 | func (SendResultType) Descriptor() protoreflect.EnumDescriptor { 53 | return file_broadcast_broadcast_proto_enumTypes[0].Descriptor() 54 | } 55 | 56 | func (SendResultType) Type() protoreflect.EnumType { 57 | return &file_broadcast_broadcast_proto_enumTypes[0] 58 | } 59 | 60 | func (x SendResultType) Number() protoreflect.EnumNumber { 61 | return protoreflect.EnumNumber(x) 62 | } 63 | 64 | // Deprecated: Use SendResultType.Descriptor instead. 65 | func (SendResultType) EnumDescriptor() ([]byte, []int) { 66 | return file_broadcast_broadcast_proto_rawDescGZIP(), []int{0} 67 | } 68 | 69 | type Channel struct { 70 | state protoimpl.MessageState 71 | sizeCache protoimpl.SizeCache 72 | unknownFields protoimpl.UnknownFields 73 | 74 | Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` 75 | Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` 76 | } 77 | 78 | func (x *Channel) Reset() { 79 | *x = Channel{} 80 | mi := &file_broadcast_broadcast_proto_msgTypes[0] 81 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 82 | ms.StoreMessageInfo(mi) 83 | } 84 | 85 | func (x *Channel) String() string { 86 | return protoimpl.X.MessageStringOf(x) 87 | } 88 | 89 | func (*Channel) ProtoMessage() {} 90 | 91 | func (x *Channel) ProtoReflect() protoreflect.Message { 92 | mi := &file_broadcast_broadcast_proto_msgTypes[0] 93 | if x != nil { 94 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 95 | if ms.LoadMessageInfo() == nil { 96 | ms.StoreMessageInfo(mi) 97 | } 98 | return ms 99 | } 100 | return mi.MessageOf(x) 101 | } 102 | 103 | // Deprecated: Use Channel.ProtoReflect.Descriptor instead. 104 | func (*Channel) Descriptor() ([]byte, []int) { 105 | return file_broadcast_broadcast_proto_rawDescGZIP(), []int{0} 106 | } 107 | 108 | func (x *Channel) GetId() string { 109 | if x != nil { 110 | return x.Id 111 | } 112 | return "" 113 | } 114 | 115 | func (x *Channel) GetName() string { 116 | if x != nil { 117 | return x.Name 118 | } 119 | return "" 120 | } 121 | 122 | type Channels struct { 123 | state protoimpl.MessageState 124 | sizeCache protoimpl.SizeCache 125 | unknownFields protoimpl.UnknownFields 126 | 127 | Channels []*Channel `protobuf:"bytes,1,rep,name=channels,proto3" json:"channels,omitempty"` 128 | } 129 | 130 | func (x *Channels) Reset() { 131 | *x = Channels{} 132 | mi := &file_broadcast_broadcast_proto_msgTypes[1] 133 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 134 | ms.StoreMessageInfo(mi) 135 | } 136 | 137 | func (x *Channels) String() string { 138 | return protoimpl.X.MessageStringOf(x) 139 | } 140 | 141 | func (*Channels) ProtoMessage() {} 142 | 143 | func (x *Channels) ProtoReflect() protoreflect.Message { 144 | mi := &file_broadcast_broadcast_proto_msgTypes[1] 145 | if x != nil { 146 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 147 | if ms.LoadMessageInfo() == nil { 148 | ms.StoreMessageInfo(mi) 149 | } 150 | return ms 151 | } 152 | return mi.MessageOf(x) 153 | } 154 | 155 | // Deprecated: Use Channels.ProtoReflect.Descriptor instead. 156 | func (*Channels) Descriptor() ([]byte, []int) { 157 | return file_broadcast_broadcast_proto_rawDescGZIP(), []int{1} 158 | } 159 | 160 | func (x *Channels) GetChannels() []*Channel { 161 | if x != nil { 162 | return x.Channels 163 | } 164 | return nil 165 | } 166 | 167 | type GetByIdRequest struct { 168 | state protoimpl.MessageState 169 | sizeCache protoimpl.SizeCache 170 | unknownFields protoimpl.UnknownFields 171 | 172 | Id *string `protobuf:"bytes,1,opt,name=id,proto3,oneof" json:"id,omitempty"` 173 | } 174 | 175 | func (x *GetByIdRequest) Reset() { 176 | *x = GetByIdRequest{} 177 | mi := &file_broadcast_broadcast_proto_msgTypes[2] 178 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 179 | ms.StoreMessageInfo(mi) 180 | } 181 | 182 | func (x *GetByIdRequest) String() string { 183 | return protoimpl.X.MessageStringOf(x) 184 | } 185 | 186 | func (*GetByIdRequest) ProtoMessage() {} 187 | 188 | func (x *GetByIdRequest) ProtoReflect() protoreflect.Message { 189 | mi := &file_broadcast_broadcast_proto_msgTypes[2] 190 | if x != nil { 191 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 192 | if ms.LoadMessageInfo() == nil { 193 | ms.StoreMessageInfo(mi) 194 | } 195 | return ms 196 | } 197 | return mi.MessageOf(x) 198 | } 199 | 200 | // Deprecated: Use GetByIdRequest.ProtoReflect.Descriptor instead. 201 | func (*GetByIdRequest) Descriptor() ([]byte, []int) { 202 | return file_broadcast_broadcast_proto_rawDescGZIP(), []int{2} 203 | } 204 | 205 | func (x *GetByIdRequest) GetId() string { 206 | if x != nil && x.Id != nil { 207 | return *x.Id 208 | } 209 | return "" 210 | } 211 | 212 | type ListRequest struct { 213 | state protoimpl.MessageState 214 | sizeCache protoimpl.SizeCache 215 | unknownFields protoimpl.UnknownFields 216 | } 217 | 218 | func (x *ListRequest) Reset() { 219 | *x = ListRequest{} 220 | mi := &file_broadcast_broadcast_proto_msgTypes[3] 221 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 222 | ms.StoreMessageInfo(mi) 223 | } 224 | 225 | func (x *ListRequest) String() string { 226 | return protoimpl.X.MessageStringOf(x) 227 | } 228 | 229 | func (*ListRequest) ProtoMessage() {} 230 | 231 | func (x *ListRequest) ProtoReflect() protoreflect.Message { 232 | mi := &file_broadcast_broadcast_proto_msgTypes[3] 233 | if x != nil { 234 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 235 | if ms.LoadMessageInfo() == nil { 236 | ms.StoreMessageInfo(mi) 237 | } 238 | return ms 239 | } 240 | return mi.MessageOf(x) 241 | } 242 | 243 | // Deprecated: Use ListRequest.ProtoReflect.Descriptor instead. 244 | func (*ListRequest) Descriptor() ([]byte, []int) { 245 | return file_broadcast_broadcast_proto_rawDescGZIP(), []int{3} 246 | } 247 | 248 | type Message struct { 249 | state protoimpl.MessageState 250 | sizeCache protoimpl.SizeCache 251 | unknownFields protoimpl.UnknownFields 252 | 253 | Body string `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` 254 | } 255 | 256 | func (x *Message) Reset() { 257 | *x = Message{} 258 | mi := &file_broadcast_broadcast_proto_msgTypes[4] 259 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 260 | ms.StoreMessageInfo(mi) 261 | } 262 | 263 | func (x *Message) String() string { 264 | return protoimpl.X.MessageStringOf(x) 265 | } 266 | 267 | func (*Message) ProtoMessage() {} 268 | 269 | func (x *Message) ProtoReflect() protoreflect.Message { 270 | mi := &file_broadcast_broadcast_proto_msgTypes[4] 271 | if x != nil { 272 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 273 | if ms.LoadMessageInfo() == nil { 274 | ms.StoreMessageInfo(mi) 275 | } 276 | return ms 277 | } 278 | return mi.MessageOf(x) 279 | } 280 | 281 | // Deprecated: Use Message.ProtoReflect.Descriptor instead. 282 | func (*Message) Descriptor() ([]byte, []int) { 283 | return file_broadcast_broadcast_proto_rawDescGZIP(), []int{4} 284 | } 285 | 286 | func (x *Message) GetBody() string { 287 | if x != nil { 288 | return x.Body 289 | } 290 | return "" 291 | } 292 | 293 | type SendRequest struct { 294 | state protoimpl.MessageState 295 | sizeCache protoimpl.SizeCache 296 | unknownFields protoimpl.UnknownFields 297 | 298 | ChannelId string `protobuf:"bytes,1,opt,name=channelId,proto3" json:"channelId,omitempty"` 299 | Message *Message `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` 300 | } 301 | 302 | func (x *SendRequest) Reset() { 303 | *x = SendRequest{} 304 | mi := &file_broadcast_broadcast_proto_msgTypes[5] 305 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 306 | ms.StoreMessageInfo(mi) 307 | } 308 | 309 | func (x *SendRequest) String() string { 310 | return protoimpl.X.MessageStringOf(x) 311 | } 312 | 313 | func (*SendRequest) ProtoMessage() {} 314 | 315 | func (x *SendRequest) ProtoReflect() protoreflect.Message { 316 | mi := &file_broadcast_broadcast_proto_msgTypes[5] 317 | if x != nil { 318 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 319 | if ms.LoadMessageInfo() == nil { 320 | ms.StoreMessageInfo(mi) 321 | } 322 | return ms 323 | } 324 | return mi.MessageOf(x) 325 | } 326 | 327 | // Deprecated: Use SendRequest.ProtoReflect.Descriptor instead. 328 | func (*SendRequest) Descriptor() ([]byte, []int) { 329 | return file_broadcast_broadcast_proto_rawDescGZIP(), []int{5} 330 | } 331 | 332 | func (x *SendRequest) GetChannelId() string { 333 | if x != nil { 334 | return x.ChannelId 335 | } 336 | return "" 337 | } 338 | 339 | func (x *SendRequest) GetMessage() *Message { 340 | if x != nil { 341 | return x.Message 342 | } 343 | return nil 344 | } 345 | 346 | type SendResponse struct { 347 | state protoimpl.MessageState 348 | sizeCache protoimpl.SizeCache 349 | unknownFields protoimpl.UnknownFields 350 | 351 | Result SendResultType `protobuf:"varint,1,opt,name=result,proto3,enum=broadcast.SendResultType" json:"result,omitempty"` 352 | Error *string `protobuf:"bytes,2,opt,name=error,proto3,oneof" json:"error,omitempty"` 353 | } 354 | 355 | func (x *SendResponse) Reset() { 356 | *x = SendResponse{} 357 | mi := &file_broadcast_broadcast_proto_msgTypes[6] 358 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 359 | ms.StoreMessageInfo(mi) 360 | } 361 | 362 | func (x *SendResponse) String() string { 363 | return protoimpl.X.MessageStringOf(x) 364 | } 365 | 366 | func (*SendResponse) ProtoMessage() {} 367 | 368 | func (x *SendResponse) ProtoReflect() protoreflect.Message { 369 | mi := &file_broadcast_broadcast_proto_msgTypes[6] 370 | if x != nil { 371 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 372 | if ms.LoadMessageInfo() == nil { 373 | ms.StoreMessageInfo(mi) 374 | } 375 | return ms 376 | } 377 | return mi.MessageOf(x) 378 | } 379 | 380 | // Deprecated: Use SendResponse.ProtoReflect.Descriptor instead. 381 | func (*SendResponse) Descriptor() ([]byte, []int) { 382 | return file_broadcast_broadcast_proto_rawDescGZIP(), []int{6} 383 | } 384 | 385 | func (x *SendResponse) GetResult() SendResultType { 386 | if x != nil { 387 | return x.Result 388 | } 389 | return SendResultType_SUCCESS 390 | } 391 | 392 | func (x *SendResponse) GetError() string { 393 | if x != nil && x.Error != nil { 394 | return *x.Error 395 | } 396 | return "" 397 | } 398 | 399 | var File_broadcast_broadcast_proto protoreflect.FileDescriptor 400 | 401 | var file_broadcast_broadcast_proto_rawDesc = []byte{ 402 | 0x0a, 0x19, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x2f, 0x62, 0x72, 0x6f, 0x61, 403 | 0x64, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x62, 0x72, 0x6f, 404 | 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x22, 0x2d, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 405 | 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 406 | 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 407 | 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x0a, 0x08, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 408 | 0x73, 0x12, 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 409 | 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x2e, 410 | 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 411 | 0x73, 0x22, 0x2c, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 412 | 0x65, 0x73, 0x74, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 413 | 0x00, 0x52, 0x02, 0x69, 0x64, 0x88, 0x01, 0x01, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x69, 0x64, 0x22, 414 | 0x0d, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x1d, 415 | 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 416 | 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x59, 0x0a, 417 | 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 418 | 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 419 | 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x07, 0x6d, 0x65, 420 | 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x72, 421 | 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 422 | 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x66, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 423 | 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 424 | 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x62, 0x72, 0x6f, 0x61, 0x64, 425 | 0x63, 0x61, 0x73, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 426 | 0x79, 0x70, 0x65, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x19, 0x0a, 0x05, 0x65, 427 | 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 428 | 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 429 | 0x2a, 0x28, 0x0a, 0x0e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x54, 0x79, 430 | 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 431 | 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, 0x32, 0x83, 0x01, 0x0a, 0x0e, 0x43, 432 | 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3a, 0x0a, 433 | 0x07, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 0x64, 0x12, 0x19, 0x2e, 0x62, 0x72, 0x6f, 0x61, 0x64, 434 | 0x63, 0x61, 0x73, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 435 | 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x2e, 436 | 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x04, 0x4c, 0x69, 0x73, 437 | 0x74, 0x12, 0x16, 0x2e, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x4c, 0x69, 438 | 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x62, 0x72, 0x6f, 0x61, 439 | 0x64, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0x00, 440 | 0x32, 0x4b, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 441 | 0x63, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x16, 0x2e, 0x62, 0x72, 0x6f, 442 | 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 443 | 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x53, 444 | 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x30, 0x5a, 445 | 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x73, 0x65, 0x72, 446 | 0x2f, 0x61, 0x63, 0x69, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 447 | 0x74, 0x6f, 0x2d, 0x67, 0x6f, 0x2f, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x62, 448 | 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 449 | } 450 | 451 | var ( 452 | file_broadcast_broadcast_proto_rawDescOnce sync.Once 453 | file_broadcast_broadcast_proto_rawDescData = file_broadcast_broadcast_proto_rawDesc 454 | ) 455 | 456 | func file_broadcast_broadcast_proto_rawDescGZIP() []byte { 457 | file_broadcast_broadcast_proto_rawDescOnce.Do(func() { 458 | file_broadcast_broadcast_proto_rawDescData = protoimpl.X.CompressGZIP(file_broadcast_broadcast_proto_rawDescData) 459 | }) 460 | return file_broadcast_broadcast_proto_rawDescData 461 | } 462 | 463 | var file_broadcast_broadcast_proto_enumTypes = make([]protoimpl.EnumInfo, 1) 464 | var file_broadcast_broadcast_proto_msgTypes = make([]protoimpl.MessageInfo, 7) 465 | var file_broadcast_broadcast_proto_goTypes = []any{ 466 | (SendResultType)(0), // 0: broadcast.SendResultType 467 | (*Channel)(nil), // 1: broadcast.Channel 468 | (*Channels)(nil), // 2: broadcast.Channels 469 | (*GetByIdRequest)(nil), // 3: broadcast.GetByIdRequest 470 | (*ListRequest)(nil), // 4: broadcast.ListRequest 471 | (*Message)(nil), // 5: broadcast.Message 472 | (*SendRequest)(nil), // 6: broadcast.SendRequest 473 | (*SendResponse)(nil), // 7: broadcast.SendResponse 474 | } 475 | var file_broadcast_broadcast_proto_depIdxs = []int32{ 476 | 1, // 0: broadcast.Channels.channels:type_name -> broadcast.Channel 477 | 5, // 1: broadcast.SendRequest.message:type_name -> broadcast.Message 478 | 0, // 2: broadcast.SendResponse.result:type_name -> broadcast.SendResultType 479 | 3, // 3: broadcast.ChannelService.GetById:input_type -> broadcast.GetByIdRequest 480 | 4, // 4: broadcast.ChannelService.List:input_type -> broadcast.ListRequest 481 | 6, // 5: broadcast.MessageService.Send:input_type -> broadcast.SendRequest 482 | 1, // 6: broadcast.ChannelService.GetById:output_type -> broadcast.Channel 483 | 2, // 7: broadcast.ChannelService.List:output_type -> broadcast.Channels 484 | 7, // 8: broadcast.MessageService.Send:output_type -> broadcast.SendResponse 485 | 6, // [6:9] is the sub-list for method output_type 486 | 3, // [3:6] is the sub-list for method input_type 487 | 3, // [3:3] is the sub-list for extension type_name 488 | 3, // [3:3] is the sub-list for extension extendee 489 | 0, // [0:3] is the sub-list for field type_name 490 | } 491 | 492 | func init() { file_broadcast_broadcast_proto_init() } 493 | func file_broadcast_broadcast_proto_init() { 494 | if File_broadcast_broadcast_proto != nil { 495 | return 496 | } 497 | file_broadcast_broadcast_proto_msgTypes[2].OneofWrappers = []any{} 498 | file_broadcast_broadcast_proto_msgTypes[6].OneofWrappers = []any{} 499 | type x struct{} 500 | out := protoimpl.TypeBuilder{ 501 | File: protoimpl.DescBuilder{ 502 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 503 | RawDescriptor: file_broadcast_broadcast_proto_rawDesc, 504 | NumEnums: 1, 505 | NumMessages: 7, 506 | NumExtensions: 0, 507 | NumServices: 2, 508 | }, 509 | GoTypes: file_broadcast_broadcast_proto_goTypes, 510 | DependencyIndexes: file_broadcast_broadcast_proto_depIdxs, 511 | EnumInfos: file_broadcast_broadcast_proto_enumTypes, 512 | MessageInfos: file_broadcast_broadcast_proto_msgTypes, 513 | }.Build() 514 | File_broadcast_broadcast_proto = out.File 515 | file_broadcast_broadcast_proto_rawDesc = nil 516 | file_broadcast_broadcast_proto_goTypes = nil 517 | file_broadcast_broadcast_proto_depIdxs = nil 518 | } 519 | -------------------------------------------------------------------------------- /pkg/sample/adapters/grpc/generated/broadcast_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | // versions: 3 | // - protoc-gen-go-grpc v1.5.1 4 | // - protoc v5.27.1 5 | // source: broadcast/broadcast.proto 6 | 7 | package generated 8 | 9 | import ( 10 | context "context" 11 | grpc "google.golang.org/grpc" 12 | codes "google.golang.org/grpc/codes" 13 | status "google.golang.org/grpc/status" 14 | ) 15 | 16 | // This is a compile-time assertion to ensure that this generated file 17 | // is compatible with the grpc package it is being compiled against. 18 | // Requires gRPC-Go v1.64.0 or later. 19 | const _ = grpc.SupportPackageIsVersion9 20 | 21 | const ( 22 | ChannelService_GetById_FullMethodName = "/broadcast.ChannelService/GetById" 23 | ChannelService_List_FullMethodName = "/broadcast.ChannelService/List" 24 | ) 25 | 26 | // ChannelServiceClient is the client API for ChannelService service. 27 | // 28 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 29 | type ChannelServiceClient interface { 30 | GetById(ctx context.Context, in *GetByIdRequest, opts ...grpc.CallOption) (*Channel, error) 31 | List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*Channels, error) 32 | } 33 | 34 | type channelServiceClient struct { 35 | cc grpc.ClientConnInterface 36 | } 37 | 38 | func NewChannelServiceClient(cc grpc.ClientConnInterface) ChannelServiceClient { 39 | return &channelServiceClient{cc} 40 | } 41 | 42 | func (c *channelServiceClient) GetById(ctx context.Context, in *GetByIdRequest, opts ...grpc.CallOption) (*Channel, error) { 43 | cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) 44 | out := new(Channel) 45 | err := c.cc.Invoke(ctx, ChannelService_GetById_FullMethodName, in, out, cOpts...) 46 | if err != nil { 47 | return nil, err 48 | } 49 | return out, nil 50 | } 51 | 52 | func (c *channelServiceClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*Channels, error) { 53 | cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) 54 | out := new(Channels) 55 | err := c.cc.Invoke(ctx, ChannelService_List_FullMethodName, in, out, cOpts...) 56 | if err != nil { 57 | return nil, err 58 | } 59 | return out, nil 60 | } 61 | 62 | // ChannelServiceServer is the server API for ChannelService service. 63 | // All implementations must embed UnimplementedChannelServiceServer 64 | // for forward compatibility. 65 | type ChannelServiceServer interface { 66 | GetById(context.Context, *GetByIdRequest) (*Channel, error) 67 | List(context.Context, *ListRequest) (*Channels, error) 68 | mustEmbedUnimplementedChannelServiceServer() 69 | } 70 | 71 | // UnimplementedChannelServiceServer must be embedded to have 72 | // forward compatible implementations. 73 | // 74 | // NOTE: this should be embedded by value instead of pointer to avoid a nil 75 | // pointer dereference when methods are called. 76 | type UnimplementedChannelServiceServer struct{} 77 | 78 | func (UnimplementedChannelServiceServer) GetById(context.Context, *GetByIdRequest) (*Channel, error) { 79 | return nil, status.Errorf(codes.Unimplemented, "method GetById not implemented") 80 | } 81 | func (UnimplementedChannelServiceServer) List(context.Context, *ListRequest) (*Channels, error) { 82 | return nil, status.Errorf(codes.Unimplemented, "method List not implemented") 83 | } 84 | func (UnimplementedChannelServiceServer) mustEmbedUnimplementedChannelServiceServer() {} 85 | func (UnimplementedChannelServiceServer) testEmbeddedByValue() {} 86 | 87 | // UnsafeChannelServiceServer may be embedded to opt out of forward compatibility for this service. 88 | // Use of this interface is not recommended, as added methods to ChannelServiceServer will 89 | // result in compilation errors. 90 | type UnsafeChannelServiceServer interface { 91 | mustEmbedUnimplementedChannelServiceServer() 92 | } 93 | 94 | func RegisterChannelServiceServer(s grpc.ServiceRegistrar, srv ChannelServiceServer) { 95 | // If the following call pancis, it indicates UnimplementedChannelServiceServer was 96 | // embedded by pointer and is nil. This will cause panics if an 97 | // unimplemented method is ever invoked, so we test this at initialization 98 | // time to prevent it from happening at runtime later due to I/O. 99 | if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { 100 | t.testEmbeddedByValue() 101 | } 102 | s.RegisterService(&ChannelService_ServiceDesc, srv) 103 | } 104 | 105 | func _ChannelService_GetById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 106 | in := new(GetByIdRequest) 107 | if err := dec(in); err != nil { 108 | return nil, err 109 | } 110 | if interceptor == nil { 111 | return srv.(ChannelServiceServer).GetById(ctx, in) 112 | } 113 | info := &grpc.UnaryServerInfo{ 114 | Server: srv, 115 | FullMethod: ChannelService_GetById_FullMethodName, 116 | } 117 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 118 | return srv.(ChannelServiceServer).GetById(ctx, req.(*GetByIdRequest)) 119 | } 120 | return interceptor(ctx, in, info, handler) 121 | } 122 | 123 | func _ChannelService_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 124 | in := new(ListRequest) 125 | if err := dec(in); err != nil { 126 | return nil, err 127 | } 128 | if interceptor == nil { 129 | return srv.(ChannelServiceServer).List(ctx, in) 130 | } 131 | info := &grpc.UnaryServerInfo{ 132 | Server: srv, 133 | FullMethod: ChannelService_List_FullMethodName, 134 | } 135 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 136 | return srv.(ChannelServiceServer).List(ctx, req.(*ListRequest)) 137 | } 138 | return interceptor(ctx, in, info, handler) 139 | } 140 | 141 | // ChannelService_ServiceDesc is the grpc.ServiceDesc for ChannelService service. 142 | // It's only intended for direct use with grpc.RegisterService, 143 | // and not to be introspected or modified (even as a copy) 144 | var ChannelService_ServiceDesc = grpc.ServiceDesc{ 145 | ServiceName: "broadcast.ChannelService", 146 | HandlerType: (*ChannelServiceServer)(nil), 147 | Methods: []grpc.MethodDesc{ 148 | { 149 | MethodName: "GetById", 150 | Handler: _ChannelService_GetById_Handler, 151 | }, 152 | { 153 | MethodName: "List", 154 | Handler: _ChannelService_List_Handler, 155 | }, 156 | }, 157 | Streams: []grpc.StreamDesc{}, 158 | Metadata: "broadcast/broadcast.proto", 159 | } 160 | 161 | const ( 162 | MessageService_Send_FullMethodName = "/broadcast.MessageService/Send" 163 | ) 164 | 165 | // MessageServiceClient is the client API for MessageService service. 166 | // 167 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 168 | type MessageServiceClient interface { 169 | Send(ctx context.Context, in *SendRequest, opts ...grpc.CallOption) (*SendResponse, error) 170 | } 171 | 172 | type messageServiceClient struct { 173 | cc grpc.ClientConnInterface 174 | } 175 | 176 | func NewMessageServiceClient(cc grpc.ClientConnInterface) MessageServiceClient { 177 | return &messageServiceClient{cc} 178 | } 179 | 180 | func (c *messageServiceClient) Send(ctx context.Context, in *SendRequest, opts ...grpc.CallOption) (*SendResponse, error) { 181 | cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) 182 | out := new(SendResponse) 183 | err := c.cc.Invoke(ctx, MessageService_Send_FullMethodName, in, out, cOpts...) 184 | if err != nil { 185 | return nil, err 186 | } 187 | return out, nil 188 | } 189 | 190 | // MessageServiceServer is the server API for MessageService service. 191 | // All implementations must embed UnimplementedMessageServiceServer 192 | // for forward compatibility. 193 | type MessageServiceServer interface { 194 | Send(context.Context, *SendRequest) (*SendResponse, error) 195 | mustEmbedUnimplementedMessageServiceServer() 196 | } 197 | 198 | // UnimplementedMessageServiceServer must be embedded to have 199 | // forward compatible implementations. 200 | // 201 | // NOTE: this should be embedded by value instead of pointer to avoid a nil 202 | // pointer dereference when methods are called. 203 | type UnimplementedMessageServiceServer struct{} 204 | 205 | func (UnimplementedMessageServiceServer) Send(context.Context, *SendRequest) (*SendResponse, error) { 206 | return nil, status.Errorf(codes.Unimplemented, "method Send not implemented") 207 | } 208 | func (UnimplementedMessageServiceServer) mustEmbedUnimplementedMessageServiceServer() {} 209 | func (UnimplementedMessageServiceServer) testEmbeddedByValue() {} 210 | 211 | // UnsafeMessageServiceServer may be embedded to opt out of forward compatibility for this service. 212 | // Use of this interface is not recommended, as added methods to MessageServiceServer will 213 | // result in compilation errors. 214 | type UnsafeMessageServiceServer interface { 215 | mustEmbedUnimplementedMessageServiceServer() 216 | } 217 | 218 | func RegisterMessageServiceServer(s grpc.ServiceRegistrar, srv MessageServiceServer) { 219 | // If the following call pancis, it indicates UnimplementedMessageServiceServer was 220 | // embedded by pointer and is nil. This will cause panics if an 221 | // unimplemented method is ever invoked, so we test this at initialization 222 | // time to prevent it from happening at runtime later due to I/O. 223 | if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { 224 | t.testEmbeddedByValue() 225 | } 226 | s.RegisterService(&MessageService_ServiceDesc, srv) 227 | } 228 | 229 | func _MessageService_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 230 | in := new(SendRequest) 231 | if err := dec(in); err != nil { 232 | return nil, err 233 | } 234 | if interceptor == nil { 235 | return srv.(MessageServiceServer).Send(ctx, in) 236 | } 237 | info := &grpc.UnaryServerInfo{ 238 | Server: srv, 239 | FullMethod: MessageService_Send_FullMethodName, 240 | } 241 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 242 | return srv.(MessageServiceServer).Send(ctx, req.(*SendRequest)) 243 | } 244 | return interceptor(ctx, in, info, handler) 245 | } 246 | 247 | // MessageService_ServiceDesc is the grpc.ServiceDesc for MessageService service. 248 | // It's only intended for direct use with grpc.RegisterService, 249 | // and not to be introspected or modified (even as a copy) 250 | var MessageService_ServiceDesc = grpc.ServiceDesc{ 251 | ServiceName: "broadcast.MessageService", 252 | HandlerType: (*MessageServiceServer)(nil), 253 | Methods: []grpc.MethodDesc{ 254 | { 255 | MethodName: "Send", 256 | Handler: _MessageService_Send_Handler, 257 | }, 258 | }, 259 | Streams: []grpc.StreamDesc{}, 260 | Metadata: "broadcast/broadcast.proto", 261 | } 262 | -------------------------------------------------------------------------------- /pkg/sample/adapters/grpc/grpc.go: -------------------------------------------------------------------------------- 1 | package sample 2 | 3 | import ( 4 | "context" 5 | "log/slog" 6 | 7 | "github.com/eser/ajan/datafx" 8 | "github.com/eser/ajan/di" 9 | "github.com/eser/ajan/grpcfx" 10 | "github.com/eser/ajan/logfx" 11 | "github.com/eser/go-service/pkg/sample/adapters/grpc/generated" 12 | "github.com/eser/go-service/pkg/sample/adapters/storage" 13 | "github.com/eser/go-service/pkg/sample/business/channels" 14 | ) 15 | 16 | type BroadcastService struct { 17 | generated.UnimplementedChannelServiceServer 18 | generated.UnimplementedMessageServiceServer 19 | 20 | logger *logfx.Logger 21 | dataRegistry *datafx.Registry 22 | } 23 | 24 | func RegisterGrpcService(container di.Container, grpcService grpcfx.GrpcService, logger *logfx.Logger, dataRegistry *datafx.Registry) { //nolint:lll 25 | bs := NewBroadcastService(logger, dataRegistry) 26 | 27 | grpcService.RegisterService(&generated.ChannelService_ServiceDesc, bs) 28 | grpcService.RegisterService(&generated.MessageService_ServiceDesc, bs) 29 | } 30 | 31 | func NewBroadcastService(logger *logfx.Logger, dataRegistry *datafx.Registry) *BroadcastService { 32 | return &BroadcastService{logger: logger, dataRegistry: dataRegistry} //nolint:exhaustruct 33 | } 34 | 35 | func (s *BroadcastService) GetById(ctx context.Context, req *generated.GetByIdRequest) (*generated.Channel, error) { 36 | queries, err := storage.NewFromDefault(s.dataRegistry) 37 | if err != nil { 38 | return nil, err //nolint:wrapcheck 39 | } 40 | 41 | service := channels.NewService(queries) 42 | 43 | channel, err := service.GetById(ctx, req.GetId()) 44 | if err != nil { 45 | return nil, err //nolint:wrapcheck 46 | } 47 | 48 | result := &generated.Channel{ 49 | Id: channel.Id, 50 | Name: channel.Name.String, 51 | } 52 | 53 | return result, nil 54 | } 55 | 56 | func (s *BroadcastService) List(ctx context.Context, req *generated.ListRequest) (*generated.Channels, error) { 57 | queries, err := storage.NewFromDefault(s.dataRegistry) 58 | if err != nil { 59 | return nil, err //nolint:wrapcheck 60 | } 61 | 62 | service := channels.NewService(queries) 63 | 64 | channels, err := service.List(ctx) 65 | if err != nil { 66 | return nil, err //nolint:wrapcheck 67 | } 68 | 69 | newChannels := make([]*generated.Channel, len(channels)) 70 | for i, channel := range channels { 71 | newChannels[i] = &generated.Channel{ 72 | Id: channel.Id, 73 | Name: channel.Name.String, 74 | } 75 | } 76 | 77 | return &generated.Channels{Channels: newChannels}, nil 78 | } 79 | 80 | func (s *BroadcastService) Send(ctx context.Context, req *generated.SendRequest) (*generated.SendResponse, error) { 81 | s.logger.Info( 82 | "Send", 83 | slog.String("channelId", req.GetChannelId()), 84 | slog.Any("message", req.GetMessage()), 85 | ) 86 | 87 | return nil, nil //nolint:nilnil 88 | } 89 | -------------------------------------------------------------------------------- /pkg/sample/adapters/http/http.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "io" 7 | "log/slog" 8 | "net/http" 9 | 10 | "github.com/eser/ajan/datafx" 11 | "github.com/eser/ajan/httpfx" 12 | "github.com/eser/ajan/httpfx/middlewares" 13 | "github.com/eser/ajan/httpfx/modules/healthcheck" 14 | "github.com/eser/ajan/httpfx/modules/openapi" 15 | "github.com/eser/ajan/httpfx/modules/profiling" 16 | "github.com/eser/ajan/lib" 17 | "github.com/eser/ajan/logfx" 18 | "github.com/eser/ajan/metricsfx" 19 | "github.com/eser/go-service/pkg/sample/adapters/storage" 20 | "github.com/eser/go-service/pkg/sample/business/channels" 21 | ) 22 | 23 | func RegisterHttpRoutes(routes *httpfx.Router, logger *logfx.Logger, dataRegistry *datafx.Registry) { 24 | routes. 25 | Route("GET /channels", func(ctx *httpfx.Context) httpfx.Result { 26 | queries, err := storage.NewFromDefault(dataRegistry) 27 | if err != nil { 28 | return ctx.Results.Error(http.StatusInternalServerError, []byte(err.Error())) 29 | } 30 | 31 | service := channels.NewService(queries) 32 | 33 | channels, err := service.List(ctx.Request.Context()) 34 | if err != nil { 35 | return ctx.Results.Error(http.StatusInternalServerError, []byte(err.Error())) 36 | } 37 | 38 | return ctx.Results.Json(channels) 39 | }). 40 | HasSummary("List channels"). 41 | HasDescription("List channels."). 42 | HasResponse(http.StatusOK) 43 | 44 | routes. 45 | Route("POST /send", func(ctx *httpfx.Context) httpfx.Result { 46 | body, err := io.ReadAll(ctx.Request.Body) 47 | if err != nil { 48 | return ctx.Results.Error(http.StatusInternalServerError, []byte(err.Error())) 49 | } 50 | 51 | var payload channels.Channel 52 | err = json.Unmarshal(body, &payload) 53 | if err != nil { 54 | return ctx.Results.Error(http.StatusBadRequest, []byte(err.Error())) 55 | } 56 | 57 | logger.Info( 58 | "Send", 59 | slog.String("id", payload.Id), 60 | slog.String("name", payload.Name.String), 61 | ) 62 | 63 | return ctx.Results.Ok() 64 | }). 65 | HasSummary("Send a message to a channel"). 66 | HasDescription("Send a message to a channel."). 67 | HasResponse(http.StatusOK) 68 | } 69 | 70 | func Run(ctx context.Context, config *httpfx.Config, metricsProvider *metricsfx.MetricsProvider, logger *logfx.Logger, dataRegistry *datafx.Registry) error { //nolint:lll 71 | routes := httpfx.NewRouter("/") 72 | httpService := httpfx.NewHttpService(config, routes, metricsProvider, logger) 73 | 74 | // http middlewares 75 | routes.Use(middlewares.ErrorHandlerMiddleware()) 76 | routes.Use(middlewares.ResolveAddressMiddleware()) 77 | routes.Use(middlewares.ResponseTimeMiddleware()) 78 | routes.Use(middlewares.CorrelationIdMiddleware()) 79 | routes.Use(middlewares.CorsMiddleware()) 80 | routes.Use(middlewares.MetricsMiddleware(httpService.InnerMetrics)) 81 | 82 | // http modules 83 | healthcheck.RegisterHttpRoutes(routes, config) 84 | openapi.RegisterHttpRoutes(routes, config) 85 | profiling.RegisterHttpRoutes(routes, config) 86 | 87 | // http routes 88 | RegisterHttpRoutes(routes, logger, dataRegistry) //nolint:contextcheck 89 | 90 | // run 91 | cleanup, err := httpService.Start(ctx) 92 | if err != nil { 93 | return err //nolint:wrapcheck 94 | } 95 | 96 | defer cleanup() 97 | 98 | lib.WaitForSignal() 99 | 100 | return nil 101 | } 102 | -------------------------------------------------------------------------------- /pkg/sample/adapters/storage/channels.sql.go: -------------------------------------------------------------------------------- 1 | // Code generated by sqlc. DO NOT EDIT. 2 | // versions: 3 | // sqlc v1.28.0 4 | // source: channels.sql 5 | 6 | package storage 7 | 8 | import ( 9 | "context" 10 | "database/sql" 11 | "errors" 12 | "github.com/eser/go-service/pkg/sample/business/channels" 13 | ) 14 | 15 | const createChannel = `-- name: CreateChannel :one 16 | insert into "channel" (id, name) 17 | values ($1, $2) returning id, name 18 | ` 19 | 20 | type CreateChannelParams struct { 21 | Id string `json:"id"` 22 | Name sql.NullString `json:"name"` 23 | } 24 | 25 | // CreateChannel 26 | // 27 | // insert into "channel" (id, name) 28 | // values ($1, $2) returning id, name 29 | func (q *Queries) CreateChannel(ctx context.Context, arg CreateChannelParams) (*channels.Channel, error) { 30 | row := q.db.QueryRowContext(ctx, createChannel, arg.Id, arg.Name) 31 | var i channels.Channel 32 | err := row.Scan(&i.Id, &i.Name) 33 | if err != nil && errors.Is(err, sql.ErrNoRows) { 34 | return nil, nil 35 | } 36 | return &i, err 37 | } 38 | 39 | const deleteChannel = `-- name: DeleteChannel :execrows 40 | delete from "channel" 41 | where id = $1 42 | ` 43 | 44 | // DeleteChannel 45 | // 46 | // delete from "channel" 47 | // where id = $1 48 | func (q *Queries) DeleteChannel(ctx context.Context, id string) (int64, error) { 49 | result, err := q.db.ExecContext(ctx, deleteChannel, id) 50 | if err != nil { 51 | return 0, err 52 | } 53 | return result.RowsAffected() 54 | } 55 | 56 | const getChannelById = `-- name: GetChannelById :one 57 | select id, name from "channel" 58 | where id = $1 59 | ` 60 | 61 | // GetChannelById 62 | // 63 | // select id, name from "channel" 64 | // where id = $1 65 | func (q *Queries) GetChannelById(ctx context.Context, id string) (*channels.Channel, error) { 66 | row := q.db.QueryRowContext(ctx, getChannelById, id) 67 | var i channels.Channel 68 | err := row.Scan(&i.Id, &i.Name) 69 | if err != nil && errors.Is(err, sql.ErrNoRows) { 70 | return nil, nil 71 | } 72 | return &i, err 73 | } 74 | 75 | const getChannelByName = `-- name: GetChannelByName :one 76 | select id, name from "channel" 77 | where name = $1 78 | ` 79 | 80 | // GetChannelByName 81 | // 82 | // select id, name from "channel" 83 | // where name = $1 84 | func (q *Queries) GetChannelByName(ctx context.Context, name sql.NullString) (*channels.Channel, error) { 85 | row := q.db.QueryRowContext(ctx, getChannelByName, name) 86 | var i channels.Channel 87 | err := row.Scan(&i.Id, &i.Name) 88 | if err != nil && errors.Is(err, sql.ErrNoRows) { 89 | return nil, nil 90 | } 91 | return &i, err 92 | } 93 | 94 | const listChannels = `-- name: ListChannels :many 95 | select id, name from "channel" 96 | ` 97 | 98 | // ListChannels 99 | // 100 | // select id, name from "channel" 101 | func (q *Queries) ListChannels(ctx context.Context) ([]*channels.Channel, error) { 102 | rows, err := q.db.QueryContext(ctx, listChannels) 103 | if err != nil { 104 | return nil, err 105 | } 106 | defer rows.Close() 107 | items := []*channels.Channel{} 108 | for rows.Next() { 109 | var i channels.Channel 110 | if err := rows.Scan(&i.Id, &i.Name); err != nil { 111 | return nil, err 112 | } 113 | items = append(items, &i) 114 | } 115 | if err := rows.Close(); err != nil { 116 | return nil, err 117 | } 118 | if err := rows.Err(); err != nil { 119 | return nil, err 120 | } 121 | return items, nil 122 | } 123 | 124 | const updateChannel = `-- name: UpdateChannel :execrows 125 | update "channel" 126 | set name = $2 127 | where id = $1 128 | ` 129 | 130 | type UpdateChannelParams struct { 131 | Id string `json:"id"` 132 | Name sql.NullString `json:"name"` 133 | } 134 | 135 | // UpdateChannel 136 | // 137 | // update "channel" 138 | // set name = $2 139 | // where id = $1 140 | func (q *Queries) UpdateChannel(ctx context.Context, arg UpdateChannelParams) (int64, error) { 141 | result, err := q.db.ExecContext(ctx, updateChannel, arg.Id, arg.Name) 142 | if err != nil { 143 | return 0, err 144 | } 145 | return result.RowsAffected() 146 | } 147 | -------------------------------------------------------------------------------- /pkg/sample/adapters/storage/db.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/eser/ajan/datafx" 8 | ) 9 | 10 | var ErrDataSourceNotFound = errors.New("data source not found") 11 | 12 | func NewFromDefault(dataRegistry *datafx.Registry) (*Queries, error) { 13 | dataSource := dataRegistry.GetDefault() 14 | 15 | if dataSource == nil { 16 | return nil, fmt.Errorf("%w - default", ErrDataSourceNotFound) 17 | } 18 | 19 | db := dataSource.GetConnection() 20 | 21 | return &Queries{db: db}, nil 22 | } 23 | 24 | func NewFromNamed(dataRegistry *datafx.Registry, name string) (*Queries, error) { 25 | dataSource := dataRegistry.GetNamed(name) 26 | 27 | if dataSource == nil { 28 | return nil, fmt.Errorf("%w - %s", ErrDataSourceNotFound, name) 29 | } 30 | 31 | db := dataSource.GetConnection() 32 | 33 | return &Queries{db: db}, nil 34 | } 35 | -------------------------------------------------------------------------------- /pkg/sample/adapters/storage/db_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by sqlc. DO NOT EDIT. 2 | // versions: 3 | // sqlc v1.28.0 4 | 5 | package storage 6 | 7 | import ( 8 | "context" 9 | "database/sql" 10 | ) 11 | 12 | type DBTX interface { 13 | ExecContext(context.Context, string, ...interface{}) (sql.Result, error) 14 | PrepareContext(context.Context, string) (*sql.Stmt, error) 15 | QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) 16 | QueryRowContext(context.Context, string, ...interface{}) *sql.Row 17 | } 18 | 19 | func New(db DBTX) *Queries { 20 | return &Queries{db: db} 21 | } 22 | 23 | type Queries struct { 24 | db DBTX 25 | } 26 | 27 | func (q *Queries) WithTx(tx *sql.Tx) *Queries { 28 | return &Queries{ 29 | db: tx, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pkg/sample/business/channels/service.go: -------------------------------------------------------------------------------- 1 | package channels 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | ) 8 | 9 | type Repository interface { 10 | GetChannelById(ctx context.Context, id string) (*Channel, error) 11 | GetChannelByName(ctx context.Context, name sql.NullString) (*Channel, error) 12 | ListChannels(ctx context.Context) ([]*Channel, error) 13 | // CreateChannel(ctx context.Context, arg CreateChannelParams) (*Channel, error) 14 | // UpdateChannel(ctx context.Context, arg UpdateChannelParams) (int64, error) 15 | // DeleteChannel(ctx context.Context, id string) (int64, error) 16 | } 17 | 18 | type Service struct { 19 | repo Repository 20 | } 21 | 22 | func NewService(repo Repository) *Service { 23 | return &Service{repo: repo} 24 | } 25 | 26 | func (s *Service) GetById(ctx context.Context, id string) (*Channel, error) { 27 | channel, err := s.repo.GetChannelById(ctx, id) 28 | if err != nil { 29 | return nil, fmt.Errorf("failed to get channel by id: %w", err) 30 | } 31 | 32 | return channel, nil 33 | } 34 | 35 | func (s *Service) GetByName(ctx context.Context, name string) (*Channel, error) { 36 | channel, err := s.repo.GetChannelByName(ctx, sql.NullString{String: name, Valid: true}) 37 | if err != nil { 38 | return nil, fmt.Errorf("failed to get channel by name: %w", err) 39 | } 40 | 41 | return channel, nil 42 | } 43 | 44 | func (s *Service) List(ctx context.Context) ([]*Channel, error) { 45 | channels, err := s.repo.ListChannels(ctx) 46 | if err != nil { 47 | return nil, fmt.Errorf("failed to list channels: %w", err) 48 | } 49 | 50 | return channels, nil 51 | } 52 | 53 | // func (s *Service) Create(ctx context.Context, channel *Channel) (*Channel, error) { 54 | // channel, err := s.repo.CreateChannel(ctx, channel) 55 | // if err != nil { 56 | // return nil, fmt.Errorf("failed to create channel: %w", err) 57 | // } 58 | 59 | // return channel, nil 60 | // } 61 | -------------------------------------------------------------------------------- /pkg/sample/business/channels/types_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by sqlc. DO NOT EDIT. 2 | // versions: 3 | // sqlc v1.28.0 4 | 5 | package channels 6 | 7 | import ( 8 | "database/sql" 9 | ) 10 | 11 | type Channel struct { 12 | Id string `json:"id"` 13 | Name sql.NullString `json:"name"` 14 | } 15 | -------------------------------------------------------------------------------- /pkg/sample/business/tenants/service.go: -------------------------------------------------------------------------------- 1 | package tenants 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | ) 8 | 9 | var ErrRecordNotFound = errors.New("record not found") 10 | 11 | type Repository interface { 12 | GetById(ctx context.Context, id string) (*Tenant, error) 13 | GetByName(ctx context.Context, name string) (*Tenant, error) 14 | List(ctx context.Context) ([]*Tenant, error) 15 | Create(ctx context.Context, tenant *Tenant) (*Tenant, error) 16 | Update(ctx context.Context, tenant *Tenant) error 17 | SoftDelete(ctx context.Context, id string) error 18 | } 19 | 20 | type Service struct { 21 | repo Repository 22 | generateID TenantIDGenerator 23 | } 24 | 25 | func NewService(repo Repository, idGenerator TenantIDGenerator) *Service { 26 | return &Service{repo: repo, generateID: idGenerator} 27 | } 28 | 29 | // create 30 | 31 | type CreateTenantArgs struct { 32 | Name string 33 | Description string 34 | } 35 | 36 | type CreateTenantResult struct { 37 | Tenant Tenant 38 | } 39 | 40 | func (s *Service) GetById(ctx context.Context, id string) (*Tenant, error) { 41 | tenant, err := s.repo.GetById(ctx, id) 42 | if err != nil { 43 | return nil, fmt.Errorf("failed to get tenant by id: %w", err) 44 | } 45 | 46 | return tenant, nil 47 | } 48 | 49 | func (s *Service) GetByName(ctx context.Context, name string) (*Tenant, error) { 50 | tenant, err := s.repo.GetByName(ctx, name) 51 | if err != nil { 52 | return nil, fmt.Errorf("failed to get tenant by name: %w", err) 53 | } 54 | 55 | return tenant, nil 56 | } 57 | 58 | func (s *Service) List(ctx context.Context) ([]*Tenant, error) { 59 | tenants, err := s.repo.List(ctx) 60 | if err != nil { 61 | return nil, fmt.Errorf("failed to list tenants: %w", err) 62 | } 63 | 64 | return tenants, nil 65 | } 66 | 67 | func (s *Service) Create(ctx context.Context, tenant *Tenant) (*Tenant, error) { 68 | tenant, err := s.repo.Create(ctx, tenant) 69 | if err != nil { 70 | return nil, fmt.Errorf("failed to create tenant: %w", err) 71 | } 72 | 73 | return tenant, nil 74 | } 75 | -------------------------------------------------------------------------------- /pkg/sample/business/tenants/types.go: -------------------------------------------------------------------------------- 1 | package tenants 2 | 3 | import "time" 4 | 5 | type TenantID string 6 | 7 | type TenantIDGenerator func() TenantID 8 | 9 | type Tenant struct { 10 | CreatedAt time.Time `json:"createdAt"` 11 | UpdatedAt time.Time `json:"updatedAt"` 12 | DeletedAt *time.Time `json:"deletedAt,omitempty"` 13 | ID TenantID `json:"id"` 14 | 15 | Name string `json:"name"` 16 | Description string `json:"description"` 17 | } 18 | -------------------------------------------------------------------------------- /sqlc.yaml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | plugins: 4 | - name: golang 5 | wasm: 6 | url: file://./bin/sqlc-gen-go.wasm 7 | sha256: "4fa2c7de11bd2ced2a0cbdf29fb737ff8c93ce65e8ab0fd78c532a8d7f64bd52" 8 | 9 | sql: 10 | # ------------------------------------------------------------ 11 | # Default 12 | # ------------------------------------------------------------ 13 | - engine: "postgresql" 14 | queries: "etc/data/default/queries/channels.sql" 15 | schema: "etc/data/default/migrations" 16 | rules: 17 | - sqlc/db-prepare 18 | codegen: 19 | - plugin: golang 20 | out: "pkg/sample" 21 | options: 22 | module: "github.com/eser/go-service/pkg/sample" 23 | sql_package: "database/sql" 24 | initialisms: [] 25 | emit_empty_slices: true 26 | emit_nil_records: true 27 | emit_json_tags: true 28 | emit_sql_as_comment: true 29 | emit_result_struct_pointers: true 30 | json_tags_case_style: "camel" 31 | output_models_package: "channels" 32 | output_models_file_name: "business/channels/types_gen.go" 33 | output_db_package: "storage" 34 | output_db_file_name: "adapters/storage/db_gen.go" 35 | output_files_package: "storage" 36 | output_files_prefix: "adapters/storage/" 37 | -------------------------------------------------------------------------------- /tmp/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eser/golang-service-template/d3ffc6feecf25585c117ecf48f817d606696d2e0/tmp/.gitkeep --------------------------------------------------------------------------------