Full Code of nats-io/nack for AI

main f6dad096d5d4 cached
177 files
926.2 KB
251.3k tokens
916 symbols
1 requests
Download .txt
Showing preview only (986K chars total). Download the full file or copy to clipboard to get everything.
Repository: nats-io/nack
Branch: main
Commit: f6dad096d5d4
Files: 177
Total size: 926.2 KB

Directory structure:
gitextract_mbhvqodb/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── config.yml
│   │   ├── defect.yml
│   │   └── proposal.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── claude.yml
│       ├── deps-release-detect.yaml
│       ├── deps-release-tag.yaml
│       ├── e2e.yaml
│       ├── release.yaml
│       └── test.yaml
├── .gitignore
├── .goreleaser.yml
├── CLAUDE.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── cicd/
│   ├── Dockerfile
│   ├── Dockerfile_goreleaser
│   ├── assets/
│   │   └── entrypoint.sh
│   └── tag-deps-version.txt
├── cmd/
│   ├── jetstream-controller/
│   │   └── main.go
│   ├── nats-boot-config/
│   │   └── main.go
│   └── nats-server-config-reloader/
│       └── main.go
├── controllers/
│   └── jetstream/
│       ├── conn_pool.go
│       ├── conn_pool_test.go
│       ├── consumer.go
│       ├── consumer_test.go
│       ├── controller.go
│       ├── controller_test.go
│       ├── jsmclient.go
│       ├── jsmclient_test.go
│       ├── stream.go
│       └── stream_test.go
├── dependencies.md
├── deploy/
│   ├── crds.yml
│   ├── examples/
│   │   ├── consumer_pull.yml
│   │   ├── consumer_push.yml
│   │   ├── stream.yml
│   │   ├── stream_mirror.yml
│   │   ├── stream_placement.yml
│   │   ├── stream_servers.yml
│   │   └── stream_sources.yml
│   └── rbac.yml
├── docker-bake.hcl
├── docs/
│   └── api.md
├── examples/
│   └── secure/
│       ├── client-tls.yaml
│       ├── issuer.yaml
│       ├── nack/
│       │   ├── account-foo.yaml
│       │   ├── nats-account-a.yaml
│       │   ├── nats-consumer-bar-a.yaml
│       │   ├── nats-stream-foo-a.yaml
│       │   └── stream-foo.yaml
│       ├── nack-a-client-tls.yaml
│       ├── nack-b-client-tls.yaml
│       ├── nats-helm.yaml
│       └── server-tls.yaml
├── go.mod
├── go.sum
├── internal/
│   └── controller/
│       ├── account_controller.go
│       ├── account_controller_test.go
│       ├── client.go
│       ├── connection_pool.go
│       ├── connection_pool_test.go
│       ├── consumer_controller.go
│       ├── consumer_controller_test.go
│       ├── helpers_test.go
│       ├── jetstream_controller.go
│       ├── jetstream_controller_test.go
│       ├── keyvalue_controller.go
│       ├── keyvalue_controller_test.go
│       ├── objectstore_controller.go
│       ├── objectstore_controller_test.go
│       ├── register.go
│       ├── stream_controller.go
│       ├── stream_controller_test.go
│       ├── suite_test.go
│       └── types.go
├── kuttl-test.yaml
├── pkg/
│   ├── bootconfig/
│   │   └── bootconfig.go
│   ├── jetstream/
│   │   ├── apis/
│   │   │   └── jetstream/
│   │   │       ├── register.go
│   │   │       ├── v1beta1/
│   │   │       │   ├── consumertypes.go
│   │   │       │   ├── doc.go
│   │   │       │   ├── register.go
│   │   │       │   ├── streamtemplatetypes.go
│   │   │       │   ├── streamtypes.go
│   │   │       │   ├── types.go
│   │   │       │   └── zz_generated.deepcopy.go
│   │   │       └── v1beta2/
│   │   │           ├── accounttypes.go
│   │   │           ├── consumertypes.go
│   │   │           ├── doc.go
│   │   │           ├── keyvaluetypes.go
│   │   │           ├── objectstoretypes.go
│   │   │           ├── register.go
│   │   │           ├── streamtypes.go
│   │   │           ├── types.go
│   │   │           └── zz_generated.deepcopy.go
│   │   └── generated/
│   │       ├── applyconfiguration/
│   │       │   ├── internal/
│   │       │   │   └── internal.go
│   │       │   ├── jetstream/
│   │       │   │   └── v1beta2/
│   │       │   │       ├── account.go
│   │       │   │       ├── accountspec.go
│   │       │   │       ├── basestreamconfig.go
│   │       │   │       ├── condition.go
│   │       │   │       ├── connectionopts.go
│   │       │   │       ├── consumer.go
│   │       │   │       ├── consumerlimits.go
│   │       │   │       ├── consumerspec.go
│   │       │   │       ├── credssecret.go
│   │       │   │       ├── keyvalue.go
│   │       │   │       ├── keyvaluespec.go
│   │       │   │       ├── nkeysecret.go
│   │       │   │       ├── objectstore.go
│   │       │   │       ├── objectstorespec.go
│   │       │   │       ├── republish.go
│   │       │   │       ├── secretref.go
│   │       │   │       ├── status.go
│   │       │   │       ├── stream.go
│   │       │   │       ├── streamplacement.go
│   │       │   │       ├── streamsource.go
│   │       │   │       ├── streamspec.go
│   │       │   │       ├── subjecttransform.go
│   │       │   │       ├── tls.go
│   │       │   │       ├── tlssecret.go
│   │       │   │       ├── tokensecret.go
│   │       │   │       └── user.go
│   │       │   └── utils.go
│   │       ├── clientset/
│   │       │   └── versioned/
│   │       │       ├── clientset.go
│   │       │       ├── fake/
│   │       │       │   ├── clientset_generated.go
│   │       │       │   ├── doc.go
│   │       │       │   └── register.go
│   │       │       ├── scheme/
│   │       │       │   ├── doc.go
│   │       │       │   └── register.go
│   │       │       └── typed/
│   │       │           └── jetstream/
│   │       │               └── v1beta2/
│   │       │                   ├── account.go
│   │       │                   ├── consumer.go
│   │       │                   ├── doc.go
│   │       │                   ├── fake/
│   │       │                   │   ├── doc.go
│   │       │                   │   ├── fake_account.go
│   │       │                   │   ├── fake_consumer.go
│   │       │                   │   ├── fake_jetstream_client.go
│   │       │                   │   ├── fake_keyvalue.go
│   │       │                   │   ├── fake_objectstore.go
│   │       │                   │   └── fake_stream.go
│   │       │                   ├── generated_expansion.go
│   │       │                   ├── jetstream_client.go
│   │       │                   ├── keyvalue.go
│   │       │                   ├── objectstore.go
│   │       │                   └── stream.go
│   │       ├── informers/
│   │       │   └── externalversions/
│   │       │       ├── factory.go
│   │       │       ├── generic.go
│   │       │       ├── internalinterfaces/
│   │       │       │   └── factory_interfaces.go
│   │       │       └── jetstream/
│   │       │           ├── interface.go
│   │       │           └── v1beta2/
│   │       │               ├── account.go
│   │       │               ├── consumer.go
│   │       │               ├── interface.go
│   │       │               ├── keyvalue.go
│   │       │               ├── objectstore.go
│   │       │               └── stream.go
│   │       └── listers/
│   │           └── jetstream/
│   │               └── v1beta2/
│   │                   ├── account.go
│   │                   ├── consumer.go
│   │                   ├── expansion_generated.go
│   │                   ├── keyvalue.go
│   │                   ├── objectstore.go
│   │                   └── stream.go
│   ├── k8scodegen/
│   │   ├── file-header.txt
│   │   └── k8scodegen.go
│   └── natsreloader/
│       ├── natsreloader.go
│       └── natsreloader_test.go
└── tests/
    ├── Dockerfile
    ├── nack-control-loop.yaml
    ├── nack-legacy.yaml
    ├── nats.yaml
    └── stream-creation/
        ├── 00-nack.yaml
        ├── 01-stream.yaml
        ├── 02-natscli-stream.yaml
        ├── asserted-natscli.yaml
        ├── asserted-rides-stream.yaml
        ├── natscli.yaml
        └── rides-stream.yaml

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
  - name: Discussion
    url: https://github.com/nats-io/nack/discussions
    about: Ideal for ideas, feedback, or longer form questions.
  - name: Chat
    url: https://slack.nats.io
    about: Ideal for short, one-off questions, general conversation, and meeting other NATS users!


================================================
FILE: .github/ISSUE_TEMPLATE/defect.yml
================================================
---
name: Defect
description: Report a defect, such as a bug or regression.
labels:
  - defect
body:
  - type: textarea
    id: versions
    attributes:
      label: What version were you using?
      description: Include the server version (`nats-server --version`) and any client versions when observing the issue.
    validations:
      required: true
  - type: textarea
    id: environment
    attributes:
      label: What environment was the server running in?
      description: This pertains to the operating system, CPU architecture, and/or Docker image that was used.
    validations:
      required: true
  - type: textarea
    id: steps
    attributes:
      label: Is this defect reproducible?
      description: Provide best-effort steps to showcase the defect.
    validations:
      required: true
  - type: textarea
    id: expected
    attributes:
      label: Given the capability you are leveraging, describe your expectation?
      description: This may be the expected behavior or performance characteristics.
    validations:
      required: true
  - type: textarea
    id: actual
    attributes:
      label: Given the expectation, what is the defect you are observing?
      description: This may be an unexpected behavior or regression in performance.
    validations:
      required: true


================================================
FILE: .github/ISSUE_TEMPLATE/proposal.yml
================================================
---
name: Proposal
description: Propose an enhancement or new feature.
labels:
  - proposal
body:
  - type: textarea
    id: usecase
    attributes:
      label: What motivated this proposal?
      description: Describe the use case justifying this request.
    validations:
      required: true
  - type: textarea
    id: change
    attributes:
      label: What is the proposed change?
      description: This could be a behavior change, enhanced API, or a branch new feature.
    validations:
      required: true
  - type: textarea
    id: benefits
    attributes:
      label: Who benefits from this change?
      description: Describe how this not only benefits you.
    validations:
      required: false
  - type: textarea
    id: alternates
    attributes:
      label: What alternatives have you evaluated?
      description: This could be using existing features or relying on an external dependency.
    validations:
      required: false


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  # version updates: enabled
  # security updates: enabled
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
    cooldown:
      default-days: 7
  - package-ecosystem: docker
    directory: /cicd
    schedule:
      interval: daily
    cooldown:
      default-days: 7

  # version updates: disabled
  # security updates: enabled
  # https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates#overriding-the-default-behavior-with-a-configuration-file
  - package-ecosystem: "gomod"
    directory: "/"
    schedule:
      interval: "daily"
    open-pull-requests-limit: 0
    cooldown:
      default-days: 7


================================================
FILE: .github/workflows/claude.yml
================================================
name: Claude Code

# GITHUB_TOKEN needs contents:read and actions:read — required by
# claude-code-action for restoring trusted config files from the base branch.
# All other GitHub API access uses the App token.
permissions:
  contents: read
  actions: read

on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]
  pull_request_target:
    types: [opened, reopened]

jobs:
  claude:
    uses: synadia-io/ai-workflows/.github/workflows/claude.yml@v2
    with:
      gh_app_id: ${{ vars.CLAUDE_GH_APP_ID }}
      checkout_mode: 'base'
      review_focus: |
        Additionally focus on:
        - Kubernetes controller reconciliation correctness (idempotency, status updates, error handling)
        - Proper use of controller-runtime patterns (watches, predicates, ownership references)
        - Go error handling (wrapped errors, sentinel errors, no swallowed errors)
    secrets:
      claude_oauth_token: ${{ secrets.CLAUDE_OAUTH_TOKEN }}
      gh_app_private_key: ${{ secrets.CLAUDE_GH_APP_PRIVATE_KEY }}


================================================
FILE: .github/workflows/deps-release-detect.yaml
================================================
name: Deps Release

on: 'pull_request'

permissions:
  contents: write

jobs:
  detect:
    name: Detect
    runs-on: ubuntu-latest
    if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          fetch-depth: 0
          persist-credentials: false

      - name: Configure Git
        run: |
          git config user.name "$GITHUB_ACTOR"
          git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
          git checkout -b "$GITHUB_HEAD_REF"

      - name: Dependabot metadata
        id: dependabot-metadata
        uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0

      - name: Install node
        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version: 18
      
      - name: Install semver
        run: |-
          npm install -g semver

      - name: Bump
        run: |-
          set -e
          push=0
          config='[
            {
              "directory": "cicd",
              "dependencyName": "alpine"
            }
          ]'
          deps_file="./cicd/tag-deps-version.txt"

          deps="${STEPS_DEPENDABOT_METADATA_OUTPUTS_UPDATED_DEPENDENCIES_JSON}"

          for i in $(seq 0 "$(("$(echo "$config" | jq length) - 1"))"); do
            directory="$(echo "$config" | jq -r ".[$i].directory")"
            dependencyName="$(echo "$config" | jq -r ".[$i].dependencyName")"
            match="$(echo "$deps" | jq ".[] | select(.directory == \"/$directory\" and .dependencyName == \"$dependencyName\")")"
            if [ -z "$match" ]; then
              continue
            fi

            updateType="$(echo "$match" | jq -r ".updateType")"
            prevVersion="$(echo "$match" | jq -r ".prevVersion")"
            newVersion="$(echo "$match" | jq -r ".newVersion")"

            echo "directory        : $directory"
            echo "dependencyName   : $dependencyName"
            echo "updateType       : $updateType"
            echo "prevVersion      : $prevVersion"
            echo "newVersion       : $newVersion"

            tagPrevVersion="$(git ls-remote 2>/dev/null \
              | grep -oE 'refs/tags/v[0-9]+\.[0-9]+\.[0-9]+' \
              | cut -d'/' -f3 \
              | xargs semver \
              | tail -n 1)"
            
            tagNewVersion="$(semver -i patch "$tagPrevVersion")"
              
            echo "$tagPrevVersion" > "$deps_file"
            echo "$tagNewVersion" >> "$deps_file"

            git add "$deps_file"
            if git commit -m "bump dependency release to $tagNewVersion"; then
              push=1
            fi
          done

          if [ "$push" = "1" ]; then
            git push -u origin "$GITHUB_HEAD_REF"
          fi
        env:
          STEPS_DEPENDABOT_METADATA_OUTPUTS_UPDATED_DEPENDENCIES_JSON: ${{ steps.dependabot-metadata.outputs.updated-dependencies-json }}


================================================
FILE: .github/workflows/deps-release-tag.yaml
================================================
name: Deps Release

on:
  push:
    branches:
      - main

permissions:
  actions: write
  contents: write

jobs:
  tag:
    name: Tag
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          fetch-depth: 0
          persist-credentials: false

      - name: Configure Git
        run: |
          git config user.name "$GITHUB_ACTOR"
          git config user.email "$GITHUB_ACTOR@users.noreply.github.com"

      - id: tag
        name: Determine tag
        run: |
          deps_file="./cicd/tag-deps-version.txt"
          old_version="$(head -n 1 "$deps_file")"
          old_ref_name="v$old_version"
          new_version="$(tail -n 1 "$deps_file")"
          new_ref_name="v$new_version"

          create=true
          if [ "$(git ls-remote origin "refs/tags/$new_ref_name" | wc -l)" = "1" ]; then
            create=false
          fi

          echo "old-version=$old_version" | tee -a "$GITHUB_OUTPUT"
          echo "old-ref-name=$old_ref_name" | tee -a "$GITHUB_OUTPUT"
          echo "new-version=$new_version" | tee -a "$GITHUB_OUTPUT"
          echo "new-ref-name=$new_ref_name" | tee -a "$GITHUB_OUTPUT"
          echo "create=$create" | tee -a "$GITHUB_OUTPUT"

      - if: ${{ fromJSON(steps.tag.outputs.create) }}
        name: Tag
        run: |
          commit="$(git rev-parse HEAD)"
          git fetch origin refs/tags/"${STEPS_TAG_OUTPUTS_OLD_REF_NAME}"
          git checkout -b deps "${STEPS_TAG_OUTPUTS_OLD_REF_NAME}"
          git restore --source="$commit" ./cicd ./.github/workflows/release.yaml
          git add ./cicd ./.github/workflows/release.yaml
          if git commit -m "bump dependency release to ${STEPS_TAG_OUTPUTS_NEW_VERSION}"; then
            git tag "${STEPS_TAG_OUTPUTS_NEW_REF_NAME}"
            git push origin "${STEPS_TAG_OUTPUTS_NEW_REF_NAME}"
          fi
        env:
          STEPS_TAG_OUTPUTS_OLD_REF_NAME: ${{ steps.tag.outputs.old-ref-name }}
          STEPS_TAG_OUTPUTS_NEW_VERSION: ${{ steps.tag.outputs.new-version }}
          STEPS_TAG_OUTPUTS_NEW_REF_NAME: ${{ steps.tag.outputs.new-ref-name }}

      - if: ${{ fromJSON(steps.tag.outputs.create) }}
        name: Trigger Release
        run: gh workflow run release.yaml --ref "${STEPS_TAG_OUTPUTS_NEW_REF_NAME}"
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          STEPS_TAG_OUTPUTS_NEW_REF_NAME: ${{ steps.tag.outputs.new-ref-name }}


================================================
FILE: .github/workflows/e2e.yaml
================================================
name: e2e

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  e2e:
    name: e2e
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - name: checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: install kuttl
        run: |
          curl -L https://github.com/kudobuilder/kuttl/releases/download/v0.24.0/kubectl-kuttl_0.24.0_linux_x86_64 -o /usr/local/bin/kubectl-kuttl
          chmod +x /usr/local/bin/kubectl-kuttl

      - name: create kind cluster
        uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0
        with:
          install_only: true

      - name: set up helm
        uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1

      - name: run e2e test
        run: make test-e2e


================================================
FILE: .github/workflows/release.yaml
================================================
name: Release
on:
  workflow_dispatch:
  push:
    tags:
      - v[0-9]+.[0-9]+.[0-9]+
jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
    - name: Checkout Source
      uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      with:
        fetch-depth: 0
        persist-credentials: false

    - name: Setup Go
      uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
      with:
        go-version-file: go.mod
        cache: false

    - name: Setup QEMU
      uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0

    - name: Setup Docker Buildx
      id: buildx
      uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0

    - name: Setup Docker Hub
      uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
      with:
        username: ${{ secrets.DOCKERHUB_USERNAME }}
        password: ${{ secrets.DOCKERHUB_CLI_TOKEN }}

    - name: Get Image Tags
      id: tags
      run: |
        version=$(sed 's/^v//' <<< ${GITHUB_REF_NAME})
        echo tags="latest,${version}" >> $GITHUB_OUTPUT

    - name: Build and Push
      uses: docker/bake-action@a66e1c87e2eca0503c343edf1d208c716d54b8a8 # v7.1.0
      with:
        source: .
        files: docker-bake.hcl
        push: true
        set: goreleaser.args.GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
      env:
        TAGS: "${{ steps.tags.outputs.tags }}"
        REGISTRY: "natsio"

    - name: Attach Release Files
      run: gh release upload ${GITHUB_REF_NAME} deploy/crds.yml deploy/rbac.yml
      env:
        GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/test.yaml
================================================
name: Test
on:
  push:
    paths-ignore:
      - '**.md'
  pull_request:
    paths-ignore:
      - '**.md'

jobs:
  test:
    name: Test
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
    - name: Checkout Source
      uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      with:
        persist-credentials: false

    - name: Setup Go
      id: setup-go
      uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
      with:
        go-version-file: go.mod

    - name: Build
      run: make build

    - name: Test
      run: make test


================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

/jetstream-controller.docker
/jetstream-controller
/nats-server-config-reloader
/nats-server-config-reloader.docker
/nats-boot-config
/nats-boot-config.docker
/tools
/bin
/.idea

/kubeconfig

# E2E test generated config
/tests/nack.yaml


================================================
FILE: .goreleaser.yml
================================================
version: 2
project_name: nack

release:
  name_template: 'Release {{.Tag}}'
  draft: true
  skip_upload: true
  github:
    owner: nats-io
    name: nack

builds:
  - id: jetstream-controller
    main: ./cmd/jetstream-controller
    binary: jetstream-controller
    ldflags: &common_ldflags
      - -s -w -X main.Version={{ if index .Env "VERSION" }}{{ .Env.VERSION }}{{ else }}{{ .Version }}{{ end }} -X main.GitInfo={{.ShortCommit}} -X main.BuildTime={{.Date}}
    tags:
      - timetzdata
    env:
      - CGO_ENABLED=0
    goos:
      - linux
    goarch:
      - amd64
      - arm64
      - arm
    goarm:
      - 6
      - 7

  - id: nats-boot-config
    main: ./cmd/nats-boot-config
    binary: nats-boot-config
    ldflags: *common_ldflags
    tags:
      - timetzdata
    env:
      - CGO_ENABLED=0
    goos:
      - linux
    goarch:
      - amd64
      - arm64
      - arm
    goarm:
      - 6
      - 7

  - id: nats-server-config-reloader
    main: ./cmd/nats-server-config-reloader
    binary: nats-server-config-reloader
    ldflags: *common_ldflags
    tags:
      - timetzdata
    env:
      - CGO_ENABLED=0
    goos:
      - linux
    goarch:
      - amd64
      - arm64
      - arm
    goarm:
      - 6
      - 7


================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

NACK (NATS Controllers for Kubernetes) is a Go-based Kubernetes operator that manages NATS JetStream resources (Streams, Consumers, Accounts, KeyValue, ObjectStore) via CRDs. It also includes a NATS server config reloader sidecar and a boot config init container.

## Build & Test Commands

```bash
make build                          # Build all binaries
make jetstream-controller           # Build main controller (with race detector)
make nats-server-config-reloader    # Build config reloader sidecar
make nats-boot-config               # Build boot config utility
make test                           # Run unit tests (go vet + envtest + go test)
make test-e2e                       # Run E2E tests with kuttl (requires kind)
make generate                       # Regenerate K8s clientset and deepcopy code
make clean                          # Remove built binaries
```

Run a single test package:
```bash
go test -race -cover -count=1 -timeout 30s ./internal/controller/...
go test -race -cover -count=1 -timeout 30s ./controllers/jetstream/...
```

Run a single test:
```bash
go test -race -count=1 -timeout 30s -run TestMyFunction ./internal/controller/...
```

Format code: `go fmt ./...`

## Architecture

### Two Controller Modes

The `jetstream-controller` binary runs in one of two modes:

- **Legacy mode** (default): Event-driven queue processing using custom informer factories. Supports only Stream and Consumer. Code in `controllers/jetstream/`.
- **Control-loop mode** (`--control-loop`): Full controller-runtime reconciliation loop. Supports all resource types (Stream, Consumer, Account, KeyValue, ObjectStore). Code in `internal/controller/`.

Entry point: `cmd/jetstream-controller/main.go` — the `--control-loop` flag selects which mode to run.

### CRD Types

All CRDs are API version `jetstream.nats.io/v1beta2`, defined in `pkg/jetstream/apis/jetstream/v1beta2/`:
- `streamtypes.go`, `consumertypes.go`, `accounttypes.go`, `keyvaluetypes.go`, `objectstoretypes.go`

Generated client code lives in `pkg/jetstream/generated/` — do not edit manually, run `make generate`.

### Controller Patterns

Controllers follow standard Kubernetes operator patterns:
- **Finalizers** for safe deletion cleanup (defined in `internal/controller/types.go`)
- **Status conditions** (Ready/Errored) tracked on each resource
- **State annotations** for reconciliation state tracking (Ready, Reconciling, Errored, Finalizing)
- **Idempotent reconciliation** — operations must be safe to retry
- **Owner references** for parent-child relationships (e.g., Consumer → Stream)

### Other Components

- `pkg/natsreloader/` — watches config files and sends SIGHUP to reload NATS server
- `pkg/bootconfig/` — init container for node-level network config

## Key Dependencies

- `sigs.k8s.io/controller-runtime` — Kubernetes controller framework (control-loop mode)
- `k8s.io/client-go` — Kubernetes client (legacy mode)
- `github.com/nats-io/nats.go` — NATS client
- `github.com/nats-io/jsm.go` — JetStream management

## Review Focus Areas

When reviewing changes, pay attention to:
- Kubernetes controller reconciliation correctness (idempotency, status updates, error handling)
- Proper use of controller-runtime patterns (watches, predicates, ownership references)
- Go error handling (wrapped errors, sentinel errors, no swallowed errors)

## Local Development

```bash
# Build and run against a local kubeconfig
make jetstream-controller
./jetstream-controller -kubeconfig ~/.kube/config -s nats://localhost:4222

# Start a local JetStream-enabled NATS server
nats-server -DV -js

# Increase log verbosity (klog flags)
./jetstream-controller -kubeconfig ~/.kube/config -s nats://localhost:4222 -v=10
```


================================================
FILE: CONTRIBUTING.md
================================================
> [!WARNING]
> This contribution guide is work in progress and is meant to be a location where more developers can contribute.

# Development
The codebase is currently fragmented into the refactored solution using today's standards for creating controllers (when
using the `--control-loop` argument) and the old variant. The old variant is found in `controllers` directory, while the
new code is found in `internal`.

## E2E testing
You may run the entire e2e suite with the accompanying updated image using:
```bash
make test-e2e
```

This command will:
1. Build a local Docker image with your changes
2. Run the full test suite in **legacy controller mode** (using `controllers/` implementation)
3. Run the full test suite in **control-loop mode** (using `internal/controller/` implementation with `--control-loop` flag)

This ensures both controller implementations are tested with your changes.

**Requirements:**
- `kind` must be installed (install via `make install-kind`)
- `kubectl-kuttl` must be installed (install via `kubectl krew install kuttl`)

# CRD Updates

## Generating types
```bash
make generate
```
will update the generated go structs after having updated the types.

## CRD and docs
CRD updates & accompanying documentation is currently updated manually.
TODO to automate this.



================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: Makefile
================================================
export GO111MODULE := on

SHELL=/usr/bin/env bash

ENVTEST_K8S_VERSION = 1.32.0

now := $(shell date -u +%Y-%m-%dT%H:%M:%S%z)
gitBranch := $(shell git rev-parse --abbrev-ref HEAD)
gitCommit := $(shell git rev-parse --short HEAD)
repoDirty := $(shell git diff --quiet || echo "-dirty")

VERSION ?= version-not-set
linkerVars := -X main.BuildTime=$(now) -X main.GitInfo=$(gitBranch)-$(gitCommit)$(repoDirty) -X main.Version=$(VERSION)
drepo ?= natsio

jetstreamSrc := $(shell find cmd/jetstream-controller pkg/jetstream internal/controller controllers/jetstream -name "*.go") pkg/jetstream/apis/jetstream/v1beta2/zz_generated.deepcopy.go

configReloaderSrc := $(shell find cmd/nats-server-config-reloader/ pkg/natsreloader/ -name "*.go")

bootConfigSrc := $(shell find cmd/nats-boot-config/ pkg/bootconfig/ -name "*.go")

# You might override this so as to use a more recent version, to update old
# generated imports, and so migrate away from old import paths and get back to
# a consistent import tree.
codeGeneratorDir ?=

default:
	# Try these (read Makefile for more recipes):
	#   make jetstream-controller
	#   make nats-server-config-reloader
	#   make nats-boot-config

generate: fetch-modules pkg/k8scodegen/file-header.txt
	rm -rf pkg/jetstream/generated
	D="$(codeGeneratorDir)"; : "$${D:=`go list -m -f '{{.Dir}}' k8s.io/code-generator`}"; \
	source "$$D/kube_codegen.sh" ; \
	kube::codegen::gen_helpers \
	  --boilerplate pkg/k8scodegen/file-header.txt \
	  pkg/jetstream/apis; \
	kube::codegen::gen_client \
		--with-watch \
		--with-applyconfig \
		--boilerplate pkg/k8scodegen/file-header.txt \
		--output-dir pkg/jetstream/generated \
		--output-pkg github.com/nats-io/nack/pkg/jetstream/generated \
		--one-input-api jetstream/v1beta2 \
		pkg/jetstream/apis

jetstream-controller: $(jetstreamSrc)
	go build -race -o $@ \
		-ldflags "$(linkerVars)" \
		github.com/nats-io/nack/cmd/jetstream-controller

jetstream-controller.docker: $(jetstreamSrc)
	CGO_ENABLED=0 GOOS=linux go build -o $@ \
		-ldflags "-s -w $(linkerVars)" \
		-tags timetzdata \
		github.com/nats-io/nack/cmd/jetstream-controller

.PHONY: jetstream-controller-docker
jetstream-controller-docker:
ifneq ($(ver),)
	REGISTRY="$(drepo)" \
	TAGS="$(ver)" \
	docker buildx bake --load \
		--set goreleaser.args.VERSION=$(ver) \
		jetstream-controller
else
	# Missing version, try this.
	# make jetstream-controller-docker ver=1.2.3
	exit 1
endif

.PHONY: jetstream-controller-dockerx
jetstream-controller-dockerx:
ifneq ($(ver),)
	# Ensure 'docker buildx ls' shows correct platforms.
	REGISTRY="$(drepo)" \
	TAGS="$(ver)" \
	PUSH=true \
	docker buildx bake --push \
		--set goreleaser.args.VERSION=$(ver) \
		jetstream-controller
else
	# Missing version, try this.
	# make jetstream-controller-dockerx ver=1.2.3
	exit 1
endif

nats-server-config-reloader: $(configReloaderSrc)
	go build -race -o $@ \
		-ldflags "$(linkerVars)" \
		github.com/nats-io/nack/cmd/nats-server-config-reloader

nats-server-config-reloader.docker: $(configReloaderSrc)
	CGO_ENABLED=0 GOOS=linux go build -o $@ \
		-ldflags "-s -w $(linkerVars)" \
		-tags timetzdata \
		github.com/nats-io/nack/cmd/nats-server-config-reloader

.PHONY: nats-server-config-reloader-docker
nats-server-config-reloader-docker:
ifneq ($(ver),)
	REGISTRY="$(drepo)" \
	TAGS="$(ver)" \
	docker buildx bake --load \
		--set goreleaser.args.VERSION=$(ver) \
		nats-server-config-reloader
else
	# Missing version, try this.
	# make nats-server-config-reloader-docker ver=1.2.3
	exit 1
endif

.PHONY: nats-server-config-reloader-dockerx
nats-server-config-reloader-dockerx:
ifneq ($(ver),)
	# Ensure 'docker buildx ls' shows correct platforms.
	REGISTRY="$(drepo)" \
	TAGS="$(ver)" \
	PUSH=true \
	docker buildx bake --push \
		--set goreleaser.args.VERSION=$(ver) \
		nats-server-config-reloader
else
	# Missing version, try this.
	# make nats-server-config-reloader-dockerx ver=1.2.3
	exit 1
endif

nats-boot-config: $(bootConfigSrc)
	go build -race -o $@ \
		-ldflags "$(linkerVars)" \
		github.com/nats-io/nack/cmd/nats-boot-config

nats-boot-config.docker: $(bootConfigSrc)
	CGO_ENABLED=0 GOOS=linux go build -o $@ \
		-ldflags "-s -w $(linkerVars)" \
		-tags timetzdata \
		github.com/nats-io/nack/cmd/nats-boot-config

.PHONY: nats-boot-config-docker
nats-boot-config-docker:
ifneq ($(ver),)
	REGISTRY="$(drepo)" \
	TAGS="$(ver)" \
	docker buildx bake --load \
		--set goreleaser.args.VERSION=$(ver) \
		nats-boot-config
else
	# Missing version, try this.
	# make nats-boot-config-docker ver=1.2.3
	exit 1
endif

.PHONY: nats-boot-config-dockerx
nats-boot-config-dockerx:
ifneq ($(ver),)
	# Ensure 'docker buildx ls' shows correct platforms.
	REGISTRY="$(drepo)" \
	TAGS="$(ver)" \
	PUSH=true \
	docker buildx bake --push \
		--set goreleaser.args.VERSION=$(ver) \
		nats-boot-config
else
	# Missing version, try this.
	# make nats-boot-config-dockerx ver=1.2.3
	exit 1
endif

.PHONY: fetch-modules
# This will error if we have removed some code to be regenerated, so we instead silence it and force success
fetch-modules:
	go list -f '{{with .Module}}{{end}}' all >/dev/null 2>&1 || true

.PHONY: build
build: jetstream-controller nats-server-config-reloader nats-boot-config

# Setup envtest tools based on a operator-sdk project makefile
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
	mkdir -p $(LOCALBIN)

# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary (ideally with version)
# $2 - package url which can be installed
# $3 - specific version of package
define go-install-tool
@[ -f $(1) ] || { \
set -e; \
package=$(2)@$(3) ;\
echo "Downloading $${package}" ;\
GOBIN=$(LOCALBIN) go install $${package} ;\
mv "$$(echo "$(1)" | sed "s/-$(3)$$//")" $(1) ;\
}
endef

ENVTEST ?= $(LOCALBIN)/setup-envtest-$(ENVTEST_VERSION)
ENVTEST_VERSION ?= release-0.20

.PHONY: envtest
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
$(ENVTEST): $(LOCALBIN)
	$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION))

.PHONY: test
test: envtest
	go vet ./controllers/... ./pkg/natsreloader/... ./internal/controller/...
	$(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path ## Get k8s binaries
	go test -race -cover -count=1 -timeout 30s ./controllers/... ./pkg/natsreloader/... ./internal/controller/...

.PHONY: test-e2e
test-e2e:
	@echo "Running e2e tests with kuttl..."
	@command -v kubectl-kuttl >/dev/null 2>&1 || { echo "kuttl not installed. Install: kubectl krew install kuttl"; exit 1; }
	kind delete cluster || true
	kind create cluster
	docker build -t nack:test -f tests/Dockerfile .
	kind load docker-image nack:test
	@echo "\n=== Testing LEGACY controller mode ==="
	cp tests/nack-legacy.yaml tests/nack.yaml && kubectl kuttl test
	@echo "\n=== Testing CONTROL-LOOP controller mode ==="
	cp tests/nack-control-loop.yaml tests/nack.yaml && kubectl kuttl test
	rm -f tests/nack.yaml

.PHONY: clean
clean:
	rm -f jetstream-controller jetstream-controller.docker \
		nats-server-config-reloader nats-server-config-reloader.docker \
		nats-boot-config nats-boot-config.docker

.PHONY: install-kind
install-kind:
	go install sigs.k8s.io/kind@v0.30.0


================================================
FILE: README.md
================================================
<img width="800" alt="nack-large" src="https://user-images.githubusercontent.com/26195/92535603-71ad9a80-f1ec-11ea-8959-cdc22b31b84a.png">

[![License Apache 2](https://img.shields.io/badge/License-Apache2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
[![Release Badge](https://github.com/nats-io/nack/actions/workflows/release.yaml/badge.svg)](https://github.com/nats-io/nack/actions/workflows/release.yaml)
[![E2E Badge](https://github.com/nats-io/nack/actions/workflows/e2e.yaml/badge.svg)](https://github.com/nats-io/nack/actions/workflows/e2e.yaml)
[![TEST Badge](https://github.com/nats-io/nack/actions/workflows/test.yaml/badge.svg)](https://github.com/nats-io/nack/actions/workflows/test.yaml)

[NATS](https://nats.io) Controllers for Kubernetes (NACK)

## Table of Contents

- [JetStream Controller](#jetstream-controller)
  - [Controller Modes](#controller-modes)
  - [Getting Started](#getting-started)
  - [Managing Multiple NATS Systems and Accounts](#managing-multiple-nats-systems-and-accounts)
  - [Creating NATS Resources](#creating-nats-resources)
  - [Getting Started with Accounts](#getting-started-with-accounts)
  - [Local Development](#local-development)
- [NATS Server Config Reloader](#nats-server-config-reloader)
- [NATS Boot Config](#nats-boot-config)

## JetStream Controller

The JetStream controllers allows you to manage [NATS JetStream](https://docs.nats.io/nats-concepts/jetstream) resources via Kubernetes CRDs.

### Controller Modes

NACK supports two controller modes with different capabilities:

| Mode | Streams | Consumers | Key/Value | Object Store | Accounts |
|------|---------|-----------|-----------|--------------|----------|
| **Legacy (default)** | ✅ | ✅ | ❌ | ❌ | ❌ |
| **Control-loop** (`--control-loop`) | ✅ | ✅ | ✅ | ✅ | ✅ |

> **Important**: Key/Value stores and Object stores are **only supported in control-loop mode**. If you create KeyValue or ObjectStore resources without enabling control-loop mode, they will not be reconciled.

Resources managed by NACK controllers are expected to _exclusively_ be managed by NACK, and configuration state will be enforced if mutated by an external client.

## [API Reference](docs/api.md)

The API reference documents all available CRD fields for Streams, Consumers, KeyValue, ObjectStore, and Account resources.

### Getting started

Install with Helm:

```sh
helm repo add nats https://nats-io.github.io/k8s/helm/charts/
helm repo update

helm upgrade --install nats nats/nats \
  --set config.jetstream.enabled=true \
  --set config.jetstream.memoryStore.enabled=true \
  --set config.cluster.enabled=true --wait

helm upgrade --install nack nats/nack \
  --set jetstream.nats.url=nats://nats.default.svc.cluster.local:4222 --wait
```

#### (Optional) Enable Experimental `controller-runtime` Controllers

> **Note**: The updated controllers will more reliably enforce resource state. If migrating from an older version of NACK, as long as all NATS resources are in-sync with NACK resources no modifications are expected.
>
> The `jetstream-controller` logs will contain a diff of any changes the controller has made.

```sh
helm upgrade nack nats/nack \
  --set jetstream.nats.url=nats://nats.default.svc.cluster.local:4222 \
  --set jetstream.additionalArgs={--control-loop} --wait
```

### Managing Multiple NATS Systems and Accounts

There are several approaches for managing multiple NATS Systems with NACK within one Kubernetes cluster. These options are not mutually exclusive.

#### 1. Run Multiple Namespaced Controllers
You can run multiple NACK controllers on the same Kubernetes cluster. Add `--set config.namespaced=true` to your install flags or set `namespaced: true` in your `values.yaml`. When set, the controller will only reconcile resources within its own namespace.

```sh
helm upgrade --install nack nats/nack \
  --create-namespace --namespace nats \
  --set namespaced=true \
  --set jetstream.nats.url=nats://nats.nats.svc.cluster.local:4222 --wait
```

#### 2. Use the Accounts Resource
The Accounts resource acts as a connection config for other resources. You may define multiple accounts for the same, or for distinct, NATS Systems.

```yaml
---
apiVersion: jetstream.nats.io/v1beta2
kind: Account
metadata:
  name: a
spec:
  name: a
  creds:
    secret:
      name: account-a-creds
  servers:
    - nats://nats.nats-a.svc.cluster.local
---
apiVersion: jetstream.nats.io/v1beta2
kind: Account
metadata:
  name: b
spec:
  name: b
  creds:
    secret:
      name: account-b-creds
  servers:
    - nats://nats.nats-b.svc.cluster.local
---
apiVersion: jetstream.nats.io/v1beta2
kind: Stream
metadata:
  name: foo-a
spec:
  name: foo
  subjects: ["foo", "foo.>"]
  storage: file
  replicas: 3
  maxAge: 1h
  account: a
---
apiVersion: jetstream.nats.io/v1beta2
kind: Stream
metadata:
  name: foo-b
spec:
  name: foo
  subjects: ["foo", "foo.>"]
  storage: file
  replicas: 3
  maxAge: 1h
  account: b
```

The above manifests will define two Account resources, each pulling credentials from a Kubernetes secret. Account `a` is configured to use the NATS Cluster in namespace `nats-a` and Account `b` is configured to use the NATS Cluster in namespace `nats-b`. The NATS clusters do not need to be in Kubernetes, this is just an example.

This will also create an identical stream, `foo`, in each cluster. **Note:** The resource names, `foo-a` and `foo-b`, must be distinct to not conflict as Kubernetes resources, but the stream names themselves are both `foo`.

See more details in the [Getting Started with Accounts](#getting-started-with-accounts) section.

#### 3. Define Connection Config in the CRD Manifest
You may define some connection options within the resource manifests directly. If not running in the newer `--control-loop` mode, set `--crd-connect`.

If running with `--control-loop`, resource-level connection config will always override any global config.

> **Note**: The `--crd-connect` flag is not required if running with `--control-loop`.

```sh
helm upgrade nack nats/nack \
  --set jetstream.additionalArgs={--crd-connect} --wait
```

#### Example Stream:
```yaml
apiVersion: jetstream.nats.io/v1beta2
kind: Stream
metadata:
  name: bar
spec:
  name: bar
  subjects: ["bar", "bar.>"]
  storage: file
  replicas: 3
  maxAge: 1h
  servers:
    - nats://nats.nats.svc.cluster.local:4222
```

### Creating NATS Resources

Let's create a stream and a couple of consumers:

```yaml
---
apiVersion: jetstream.nats.io/v1beta2
kind: Stream
metadata:
  name: mystream
spec:
  name: mystream
  subjects: ["orders.*"]
  storage: memory
  maxAge: 1h
---
apiVersion: jetstream.nats.io/v1beta2
kind: Consumer
metadata:
  name: my-push-consumer
spec:
  streamName: mystream
  durableName: my-push-consumer
  deliverSubject: my-push-consumer.orders
  deliverPolicy: last
  ackPolicy: none
  replayPolicy: instant
---
apiVersion: jetstream.nats.io/v1beta2
kind: Consumer
metadata:
  name: my-pull-consumer
spec:
  streamName: mystream
  durableName: my-pull-consumer
  deliverPolicy: all
  filterSubject: orders.received
  maxDeliver: 20
  ackPolicy: explicit
---
# Note: KeyValue requires control-loop mode to be enabled
apiVersion: jetstream.nats.io/v1beta2
kind: KeyValue
metadata:
  name: my-key-value
spec:
  bucket: my-key-value
  history: 20
  storage: file
  maxBytes: 2048
  compression: true
---
# Note: ObjectStore requires control-loop mode to be enabled
apiVersion: jetstream.nats.io/v1beta2
kind: ObjectStore
metadata:
  name: my-object-store
spec:
  bucket: my-object-store
  storage: file
  replicas: 1
  maxBytes: 536870912 # 512 MB
  compression: true
```

```sh
# Create a stream.
$ kubectl apply -f https://raw.githubusercontent.com/nats-io/nack/main/deploy/examples/stream.yml

# Check if it was successfully created.
$ kubectl get streams
NAME       STATE     STREAM NAME   SUBJECTS
mystream   Ready     mystream      [orders.*]

# Create a push-based consumer
$ kubectl apply -f https://raw.githubusercontent.com/nats-io/nack/main/deploy/examples/consumer_push.yml

# Create a pull based consumer
$ kubectl apply -f https://raw.githubusercontent.com/nats-io/nack/main/deploy/examples/consumer_pull.yml

# Check if they were successfully created.
$ kubectl get consumers
NAME               STATE     STREAM     CONSUMER           ACK POLICY
my-pull-consumer   Ready     mystream   my-pull-consumer   explicit
my-push-consumer   Ready     mystream   my-push-consumer   none

# If you end up in an Errored state, run kubectl describe for more info.
#     kubectl describe streams mystream
#     kubectl describe consumers my-pull-consumer
```

Now we're ready to use Streams and Consumers. Let's start off with writing some
data into `mystream`.

```sh
# Run nats-box that includes the NATS management utilities, and exec into it.
$ kubectl exec -it deployment/nats-box -- /bin/sh -l

# Publish a couple of messages from nats-box
nats-box:~$ nats pub orders.received "order 1"
nats-box:~$ nats pub orders.received "order 2"
```

First, we'll read the data using a pull-based consumer.

From the above `my-pull-consumer` Consumer CRD, we have set the filterSubject
of `orders.received`. You can double check with the following command:

```sh
$ kubectl get consumer my-pull-consumer -o jsonpath={.spec.filterSubject}
orders.received
```

So that's the subject my-pull-consumer will pull messages from.

```sh
# Pull first message.
nats-box:~$ nats consumer next mystream my-pull-consumer
--- subject: orders.received / delivered: 1 / stream seq: 1 / consumer seq: 1

order 1

Acknowledged message

# Pull next message.
nats-box:~$ nats consumer next mystream my-pull-consumer
--- subject: orders.received / delivered: 1 / stream seq: 2 / consumer seq: 2

order 2

Acknowledged message
```

Next, let's read data using a push-based consumer.

From the above `my-push-consumer` Consumer CRD, we have set the deliverSubject
of `my-push-consumer.orders`, as you can confirm with the following command:

```sh
$ kubectl get consumer my-push-consumer -o jsonpath={.spec.deliverSubject}
my-push-consumer.orders
```

So pushed messages will arrive on that subject. This time all messages arrive automatically.

```sh
nats-box:~$ nats sub my-push-consumer.orders
17:57:24 Subscribing on my-push-consumer.orders
[#1] Received JetStream message: consumer: mystream > my-push-consumer / subject: orders.received /
delivered: 1 / consumer seq: 1 / stream seq: 1 / ack: false
order 1

[#2] Received JetStream message: consumer: mystream > my-push-consumer / subject: orders.received /
delivered: 1 / consumer seq: 2 / stream seq: 2 / ack: false
order 2
```

### Getting Started with Accounts

You can create an Account resource with the following CRD. The Account resource
can be used to specify server and TLS information.

> **Note** The `Account` resource does not create or manage NATS accounts. It functions as a connection and authentication config for the managed resources.

The [nsc](https://docs.nats.io/using-nats/nats-tools/nsc/basics#creating-an-operator-account-and-user) tool can be used to manage your NATS account configuration on the server-side. You can find more details about NATS decentralized auth in the [docs](https://docs.nats.io/running-a-nats-service/configuration/securing_nats/auth_intro/jwt).

```yaml
---
apiVersion: jetstream.nats.io/v1beta2
kind: Account
metadata:
  name: a
spec:
  name: a
  servers:
    - nats://nats:4222
  tls:
    secret:
      name: nack-a-tls
    ca: "ca.crt"
    cert: "tls.crt"
    key: "tls.key"
```

You can then link an Account to a Stream so that the Stream uses the Account
information for its creation.

```yaml
---
apiVersion: jetstream.nats.io/v1beta2
kind: Stream
metadata:
  name: foo
spec:
  name: foo
  subjects: ["foo", "foo.>"]
  storage: file
  replicas: 1
  account: a # <-- Create stream using account A information
```

The following is an example of how to get Accounts working with a custom NATS
Server URL and TLS certificates.

```sh
# Install cert-manager
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.17.0/cert-manager.yaml

# Install TLS certs
cd examples/secure

# Install certificate issuer
kubectl apply -f issuer.yaml

# Install account A cert
kubectl apply -f nack-a-client-tls.yaml

# Install server cert
kubectl apply -f server-tls.yaml

# Install nats-box cert
kubectl apply -f client-tls.yaml

# Install NATS cluster
helm upgrade --install -f nats-helm.yaml nats nats/nats

# Verify pods are healthy
kubectl get pods

# Install JetStream Controller from nack
helm upgrade --install nack nats/nack --set jetstream.enabled=true

# Verify pods are healthy
kubectl get pods

# Create account A resource
kubectl apply -f nack/nats-account-a.yaml

# Create stream using account A
kubectl apply -f nack/nats-stream-foo-a.yaml

# Create consumer using account A
kubectl apply -f nack/nats-consumer-bar-a.yaml
```

After Accounts, Streams, and Consumers are created, let's log into the nats-box
container to run the management CLI.

```sh
# Get container shell
kubectl exec -it deployment/nats-box -- /bin/sh -l
```

There should now be some Streams available, verify with `nats` command.

```sh
# List streams
nats stream ls
```

You can now publish messages on a Stream.

```sh
# Push message
nats pub foo hi
```

And pull messages from a Consumer.

```sh
# Pull message
nats consumer next foo bar
```

### Local Development

```sh
# First, build the jetstream controller.
make jetstream-controller

# Next, run the controller like this
./jetstream-controller -kubeconfig ~/.kube/config -s nats://localhost:4222

# Pro tip: jetstream-controller uses klog just like kubectl or kube-apiserver.
# This means you can change the verbosity of logs with the -v flag.
#
# For example, this prints raw HTTP requests and responses.
#     ./jetstream-controller -v=10

# You'll probably want to start a local Jetstream-enabled NATS server, unless
# you use a public one.
nats-server -DV -js
```

Build Docker image

```sh
make jetstream-controller-docker ver=1.2.3
```

## NATS Server Config Reloader

This is a sidecar that you can use to automatically reload your NATS Server
configuration file.

### Installing with Helm

For more information see the
[Chart repo](https://github.com/nats-io/k8s/tree/main/helm/charts/nats).

```sh
helm repo add nats https://nats-io.github.io/k8s/helm/charts/
helm upgrade --install nats nats/nats
```

### Configuring

```yaml
reloader:
  enabled: true
  image: natsio/nats-server-config-reloader:0.16.1
  pullPolicy: IfNotPresent
```

### Local Development

```sh
# First, build the config reloader.
make nats-server-config-reloader

# Next, run the reloader like this
./nats-server-config-reloader
```

Build Docker image

```sh
make nats-server-config-reloader-docker ver=1.2.3
```

## NATS Boot Config

A helper utility used during NATS server pod initialization to generate and manage boot-time configuration.

### Installing with Helm

For more information see the
[Chart repo](https://github.com/nats-io/k8s/tree/main/helm/charts/nats).

```sh
helm repo add nats https://nats-io.github.io/k8s/helm/charts/
helm upgrade --install nats nats/nats
```

### Configuring

```yaml
bootconfig:
  image: natsio/nats-boot-config:0.16.1
  pullPolicy: IfNotPresent
```

### Local Development

```sh
# First, build the project.
make nats-boot-config

# Next, run the project like this
./nats-boot-config
```

Build Docker image

```sh
make nats-boot-config-docker ver=1.2.3
```


================================================
FILE: cicd/Dockerfile
================================================
#syntax=docker/dockerfile:1.13
ARG GO_APP

FROM alpine:3.23.3 AS deps

ARG GO_APP
ARG GORELEASER_DIST_DIR=/go/src/dist

ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT

RUN mkdir -p /go/bin /go/src ${GORELEASER_DIST_DIR}

COPY --from=build ${GORELEASER_DIST_DIR}/ ${GORELEASER_DIST_DIR}

RUN <<EOT
  set -e 
  apk add --no-cache ca-certificates jq
  cd ${GORELEASER_DIST_DIR}/..

  if [[ ${TARGETARCH} == "arm" ]]; then VARIANT=$(echo ${TARGETVARIANT} | sed 's/^v//'); fi
  BIN_PATH=$(jq -r ".[] |select(.type   == \"Binary\" and \
                                .name   == \"${GO_APP}\" and \
                                .goos   == \"${TARGETOS}\" and \
                                .goarch == \"${TARGETARCH}\" and \
                                (.goarm == \"${VARIANT}\" or .goarm == null)) | .path" < /go/src/dist/artifacts.json)
  cp ${BIN_PATH} /go/bin
EOT

FROM alpine:3.23.3

ARG GO_APP
ENV GO_APP ${GO_APP}

COPY --from=deps --chmod=755 /go/bin/${GO_APP} /usr/local/bin/${GO_APP}

COPY --from=deps /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

COPY --from=assets entrypoint.sh /entrypoint.sh

RUN ln -s /usr/local/bin/${GO_APP} /${GO_APP} && chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]


================================================
FILE: cicd/Dockerfile_goreleaser
================================================
#syntax=docker/dockerfile:1.13
FROM --platform=$BUILDPLATFORM golang:1.25.6-bookworm AS build


RUN <<EOT
    set -e

    echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' > /etc/apt/sources.list.d/goreleaser.list
    apt-get update
    apt-get install -y goreleaser
    rm -rf /var/lib/apt/lists/*
EOT

FROM build

ARG CI
ARG PUSH
ARG GITHUB_TOKEN
ARG TAGS
ARG VERSION

COPY --from=src . /go/src

RUN <<EOT
  set -e
  cd /go/src
  FLAGS="--clean"
  if [ -z ${GITHUB_TOKEN} ]; then
    if [ ${CI} != "true" ]; then FLAGS="${FLAGS} --skip=validate"; fi
    if [ ${PUSH} != "true" ]; then FLAGS="${FLAGS} --single-target"; fi
    goreleaser build ${FLAGS}
  else
    goreleaser release ${FLAGS}
  fi
EOT


================================================
FILE: cicd/assets/entrypoint.sh
================================================
#!/bin/sh
exec "/${GO_APP}" "$@"


================================================
FILE: cicd/tag-deps-version.txt
================================================
0.21.0
0.21.1


================================================
FILE: cmd/jetstream-controller/main.go
================================================
// Copyright 2020-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"
	"time"

	"github.com/nats-io/nack/controllers/jetstream"
	"github.com/nats-io/nack/internal/controller"
	v1beta2 "github.com/nats-io/nack/pkg/jetstream/apis/jetstream/v1beta2"
	clientset "github.com/nats-io/nack/pkg/jetstream/generated/clientset/versioned"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/client-go/kubernetes"
	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	klog "k8s.io/klog/v2"
	"sigs.k8s.io/controller-runtime/pkg/cache"

	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/healthz"
	"sigs.k8s.io/controller-runtime/pkg/log"
)

var (
	BuildTime = "build-time-not-set"
	GitInfo   = "gitinfo-not-set"
	Version   = "not-set"
)

func main() {
	if err := run(); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		os.Exit(1)
	}
}

func run() error {
	klog.InitFlags(nil)
	// Opt into the new klog behavior so that -stderrthreshold is honored even
	// when -logtostderr=true (the default).
	// Ref: kubernetes/klog#212, kubernetes/klog#432
	_ = flag.Set("legacy_stderr_threshold_behavior", "false")
	_ = flag.Set("stderrthreshold", "INFO")

	// Explicitly register controller-runtime flags
	ctrl.RegisterFlags(nil)

	namespace := flag.String("namespace", v1.NamespaceAll, "Restrict to a namespace")
	version := flag.Bool("version", false, "Print the version and exit")
	creds := flag.String("creds", "", "NATS Credentials")
	nkey := flag.String("nkey", "", "NATS NKey")
	cert := flag.String("tlscert", "", "NATS TLS public certificate")
	key := flag.String("tlskey", "", "NATS TLS private key")
	ca := flag.String("tlsca", "", "NATS TLS certificate authority chain")
	tlsfirst := flag.Bool("tlsfirst", false, "If enabled, forces explicit TLS without waiting for Server INFO")
	server := flag.String("s", "", "NATS Server URL")
	crdConnect := flag.Bool("crd-connect", false, "If true, then NATS connections will be made from CRD config, not global config. Ignored if running with control loop, CRD options will always override global config")
	cleanupPeriod := flag.Duration("cleanup-period", 30*time.Second, "Period to run object cleanup")
	readOnly := flag.Bool("read-only", false, "Starts the controller without causing changes to the NATS resources")
	cacheDir := flag.String("cache-dir", "", "Directory to store cached credential and TLS files")
	controlLoop := flag.Bool("control-loop", false, "Experimental: Run controller with a full reconciliation control loop")
	controlLoopSyncInterval := flag.Duration("sync-interval", time.Minute, "Interval to perform scheduled reconcile")
	healthProbeBindAddress := flag.String("health-probe-bind-address", ":8081", "The address the probe endpoint binds to")

	flag.Parse()

	if *version {
		fmt.Printf("%s version %s (%s), built %s\n", os.Args[0], Version, GitInfo, BuildTime)
		return nil
	}

	if *server == "" && !*crdConnect {
		return errors.New("NATS Server URL is required")
	}

	config, err := ctrl.GetConfig()
	if err != nil {
		return fmt.Errorf("get kubernetes rest config: %w", err)
	}

	if *controlLoop {
		klog.Warning("Starting JetStream controller in experimental control loop mode")

		natsCfg := &controller.NatsConfig{
			ClientName:  "jetstream-controller",
			Credentials: *creds,
			NKey:        *nkey,
			ServerURL:   *server,
			CAs:         []string{},
			Certificate: *cert,
			Key:         *key,
			TLSFirst:    *tlsfirst,
		}

		if *ca != "" {
			natsCfg.CAs = []string{*ca}
		}

		controllerCfg := &controller.Config{
			ReadOnly:               *readOnly,
			Namespace:              *namespace,
			CacheDir:               *cacheDir,
			RequeueInterval:        *controlLoopSyncInterval,
			HealthProbeBindAddress: *healthProbeBindAddress,
		}

		return runControlLoop(config, natsCfg, controllerCfg)
	}

	// K8S API Client.
	kc, err := kubernetes.NewForConfig(config)
	if err != nil {
		return err
	}

	// JetStream CRDs client.
	jc, err := clientset.NewForConfig(config)
	if err != nil {
		return err
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	ctrl := jetstream.NewController(jetstream.Options{
		// FIXME: Move context to be param from Run
		// to avoid keeping state in options.
		Ctx:             ctx,
		NATSCredentials: *creds,
		NATSNKey:        *nkey,
		NATSServerURL:   *server,
		NATSCA:          *ca,
		NATSCertificate: *cert,
		NATSKey:         *key,
		NATSTLSFirst:    *tlsfirst,
		KubeIface:       kc,
		JetstreamIface:  jc,
		Namespace:       *namespace,
		CRDConnect:      *crdConnect,
		CleanupPeriod:   *cleanupPeriod,
		ReadOnly:        *readOnly,
	})

	klog.Infof("Starting %s v%s...", os.Args[0], Version)
	klog.Infof("Running in LEGACY mode")
	if *readOnly {
		klog.Infof("Running in read-only mode: JetStream state in server will not be changed")
	}
	go handleSignals(cancel)
	return ctrl.Run()
}

func runControlLoop(config *rest.Config, natsCfg *controller.NatsConfig, controllerCfg *controller.Config) error {
	// Setup scheme
	scheme := runtime.NewScheme()
	utilruntime.Must(clientgoscheme.AddToScheme(scheme))
	utilruntime.Must(v1beta2.AddToScheme(scheme))

	log.SetLogger(klog.NewKlogr())

	ctrlOpts := ctrl.Options{
		Scheme:                 scheme,
		Logger:                 log.Log,
		HealthProbeBindAddress: controllerCfg.HealthProbeBindAddress,
	}

	if controllerCfg.Namespace != "" {
		ctrlOpts.Cache = cache.Options{
			DefaultNamespaces: map[string]cache.Config{
				controllerCfg.Namespace: {},
			},
		}
	}

	mgr, err := ctrl.NewManager(config, ctrlOpts)
	if err != nil {
		return fmt.Errorf("unable to start manager: %w", err)
	}

	if controllerCfg.CacheDir == "" {
		cacheDir, err := os.MkdirTemp(".", "nack")
		if err != nil {
			return fmt.Errorf("create cache dir: %w", err)
		}
		defer os.RemoveAll(cacheDir)
		cacheDir, err = filepath.Abs(cacheDir)
		if err != nil {
			return fmt.Errorf("get absolute cache dir: %w", err)
		}
		controllerCfg.CacheDir = cacheDir
	} else {
		if _, err := os.Stat(controllerCfg.CacheDir); os.IsNotExist(err) {
			err = os.MkdirAll(controllerCfg.CacheDir, 0o755)
			if err != nil {
				return fmt.Errorf("create cache dir: %w", err)
			}
		}
	}

	err = controller.RegisterAll(mgr, natsCfg, controllerCfg)
	if err != nil {
		return fmt.Errorf("register jetstream controllers: %w", err)
	}

	if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
		return fmt.Errorf("unable to set up health check: %w", err)
	}
	if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
		return fmt.Errorf("unable to set up ready check: %w", err)
	}

	klog.Info("starting manager")
	klog.Infof("Running in CONTROL-LOOP mode")
	if controllerCfg.ReadOnly {
		klog.Infof("Running in read-only mode: JetStream state in server will not be changed")
	}
	return mgr.Start(ctrl.SetupSignalHandler())
}

func handleSignals(cancel context.CancelFunc) {
	sigc := make(chan os.Signal, 2)
	signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)

	for sig := range sigc {
		switch sig {
		case syscall.SIGINT:
			os.Exit(130)
		case syscall.SIGTERM:
			cancel()
			return
		}
	}
}


================================================
FILE: cmd/nats-boot-config/main.go
================================================
// Copyright 2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"context"
	"flag"
	"fmt"
	"os"

	"github.com/nats-io/nack/pkg/bootconfig"
	log "github.com/sirupsen/logrus"
)

var (
	BuildTime = "build-time-not-set"
	GitInfo   = "gitinfo-not-set"
	Version   = "version-not-set"
)

func main() {
	fs := flag.NewFlagSet("nats-pod-bootconfig", flag.ExitOnError)
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: nats-pod-bootconfig [options...]\n\n")
		fs.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\n")
	}

	var opts *bootconfig.Options = &bootconfig.Options{}
	var showHelp, showVersion bool
	fs.BoolVar(&showHelp, "h", false, "Show help")
	fs.BoolVar(&showVersion, "v", false, "Show version")
	fs.StringVar(&opts.ClientAdvertiseFileName, "f", "client_advertise.conf", "File name where the client advertise address will be written into")
	fs.StringVar(&opts.GatewayAdvertiseFileName, "gf", "gateway_advertise.conf", "File name where the gateway advertise address will be written into")
	fs.StringVar(&opts.TargetTag, "t", "nats.io/node-external-ip", "Tag that will be looked up from a node")
	fs.Parse(os.Args[1:])

	switch {
	case showHelp:
		flag.Usage()
		os.Exit(0)
	case showVersion:
		fmt.Fprintf(os.Stderr, "NATS Server Pod boot config v%s (%s, %s)\n", Version, GitInfo, BuildTime)
		os.Exit(0)
	}
	if os.Getenv("DEBUG") == "true" {
		log.SetLevel(log.DebugLevel)
	}
	formatter := &log.TextFormatter{
		FullTimestamp: true,
	}
	log.SetFormatter(formatter)

	controller := bootconfig.NewController(opts)
	log.Infof("Starting NATS Server boot config v%s (%s, %s)", Version, GitInfo, BuildTime)
	err := controller.Run(context.Background())
	if err != nil && err != context.Canceled {
		log.Fatalf(err.Error())
	}
}


================================================
FILE: cmd/nats-server-config-reloader/main.go
================================================
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/nats-io/nack/pkg/natsreloader"
)

var (
	BuildTime = "build-time-not-set"
	GitInfo   = "gitinfo-not-set"
	Version   = "version-not-set"
)

// StringSet is a wrapper for []string to allow using it with the flags package.
type StringSet []string

func (s *StringSet) String() string {
	return strings.Join([]string(*s), ", ")
}

// Set appends the value provided to the list of strings.
func (s *StringSet) Set(val string) error {
	*s = append(*s, val)
	return nil
}

func main() {
	fs := flag.NewFlagSet("nats-server-config-reloader", flag.ExitOnError)
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: nats-server-config-reloader [options...]\n\n")
		fs.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\n")
	}

	// Help and version
	var (
		showHelp          bool
		showVersion       bool
		fileSet           StringSet
		customSignal      int
		forcePoll         bool
		pollInterval      time.Duration
		maxWatcherRetries int
	)

	nconfig := &natsreloader.Config{}
	fs.BoolVar(&showHelp, "h", false, "Show help")
	fs.BoolVar(&showHelp, "help", false, "Show help")
	fs.BoolVar(&showVersion, "v", false, "Show version")
	fs.BoolVar(&showVersion, "version", false, "Show version")

	fs.StringVar(&nconfig.PidFile, "P", "/var/run/nats/nats.pid", "NATS Server Pid File")
	fs.StringVar(&nconfig.PidFile, "pid", "/var/run/nats/nats.pid", "NATS Server Pid File")
	fs.Var(&fileSet, "c", "NATS Server Config File (may be repeated to specify more than one)")
	fs.Var(&fileSet, "config", "NATS Server Config File (may be repeated to specify more than one)")
	fs.IntVar(&nconfig.MaxRetries, "max-retries", 30, "Max attempts to trigger reload")
	fs.IntVar(&nconfig.RetryWaitSecs, "retry-wait-secs", 4, "Time to back off when reloading fails before retrying")
	fs.IntVar(&customSignal, "signal", 1, "Signal to send to the NATS Server process (default SIGHUP 1)")
	fs.BoolVar(&forcePoll, "force-poll", false, "Force polling mode instead of inotify file watching")
	fs.DurationVar(&pollInterval, "poll-interval", 5*time.Second, "Polling interval when using polling mode (default 5s)")
	fs.IntVar(&maxWatcherRetries, "max-watcher-retries", 3, "Max retries for creating inotify watcher on transient failures")

	fs.Parse(os.Args[1:])

	nconfig.WatchedFiles = fileSet
	if len(fileSet) == 0 {
		nconfig.WatchedFiles = []string{"/etc/nats-config/nats.conf"}
	}
	nconfig.Signal = syscall.Signal(customSignal)
	nconfig.ForcePoll = forcePoll
	nconfig.PollInterval = pollInterval
	nconfig.MaxWatcherRetries = maxWatcherRetries

	switch {
	case showHelp:
		flag.Usage()
		os.Exit(0)
	case showVersion:
		fmt.Fprintf(os.Stderr, "NATS Server Config Reloader v%s (%s, %s)\n", Version, GitInfo, BuildTime)
		os.Exit(0)
	}
	r, err := natsreloader.NewReloader(nconfig)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		os.Exit(1)
	}

	// Signal handling.
	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)

		for sig := range c {
			log.Printf("Trapped \"%v\" signal\n", sig)
			switch sig {
			case syscall.SIGINT:
				log.Println("Exiting...")
				os.Exit(0)
				return
			case syscall.SIGTERM:
				r.Stop()
				return
			}
		}
	}()

	log.Printf("Starting NATS Server Reloader v%s\n", Version)
	err = r.Run(context.Background())
	if err != nil && err != context.Canceled {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		os.Exit(1)
	}
}


================================================
FILE: controllers/jetstream/conn_pool.go
================================================
package jetstream

import (
	"crypto/sha256"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"os"
	"sync"

	"github.com/nats-io/nats.go"
	"github.com/sirupsen/logrus"
	"golang.org/x/sync/singleflight"
)

type natsContext struct {
	Name        string   `json:"name"`
	URL         string   `json:"url"`
	JWT         string   `json:"jwt"`
	Seed        string   `json:"seed"`
	Credentials string   `json:"credential"`
	Nkey        string   `json:"nkey"`
	Token       string   `json:"token"`
	Username    string   `json:"username"`
	Password    string   `json:"password"`
	TLSCAs      []string `json:"tls_ca"`
	TLSCert     string   `json:"tls_cert"`
	TLSKey      string   `json:"tls_key"`
}

func (c *natsContext) copy() *natsContext {
	if c == nil {
		return nil
	}
	cp := *c
	return &cp
}

func (c *natsContext) hash() (string, error) {
	b, err := json.Marshal(c)
	if err != nil {
		return "", fmt.Errorf("error marshaling context to json: %v", err)
	}
	if c.Nkey != "" {
		fb, err := os.ReadFile(c.Nkey)
		if err != nil {
			return "", fmt.Errorf("error opening nkey file %s: %v", c.Nkey, err)
		}
		b = append(b, fb...)
	}
	if c.Credentials != "" {
		fb, err := os.ReadFile(c.Credentials)
		if err != nil {
			return "", fmt.Errorf("error opening creds file %s: %v", c.Credentials, err)
		}
		b = append(b, fb...)
	}
	if len(c.TLSCAs) > 0 {
		for _, cert := range c.TLSCAs {
			fb, err := os.ReadFile(cert)
			if err != nil {
				return "", fmt.Errorf("error opening ca file %s: %v", cert, err)
			}
			b = append(b, fb...)
		}
	}
	if c.TLSCert != "" {
		fb, err := os.ReadFile(c.TLSCert)
		if err != nil {
			return "", fmt.Errorf("error opening cert file %s: %v", c.TLSCert, err)
		}
		b = append(b, fb...)
	}
	if c.TLSKey != "" {
		fb, err := os.ReadFile(c.TLSKey)
		if err != nil {
			return "", fmt.Errorf("error opening key file %s: %v", c.TLSKey, err)
		}
		b = append(b, fb...)
	}
	hash := sha256.New()
	hash.Write(b)
	return fmt.Sprintf("%x", hash.Sum(nil)), nil
}

type natsContextDefaults struct {
	Name      string
	URL       string
	TLSCAs    []string
	TLSCert   string
	TLSKey    string
	TLSConfig *tls.Config
}

type pooledNatsConn struct {
	nc     *nats.Conn
	cp     *natsConnPool
	key    string
	count  uint64
	closed bool
}

func (pc *pooledNatsConn) ReturnToPool() {
	pc.cp.Lock()
	pc.count--
	if pc.count == 0 {
		if pooledConn, ok := pc.cp.cache[pc.key]; ok && pc == pooledConn {
			delete(pc.cp.cache, pc.key)
		}
		pc.closed = true
		pc.cp.Unlock()
		pc.nc.Close()
		return
	}
	pc.cp.Unlock()
}

type natsConnPool struct {
	sync.Mutex
	cache        map[string]*pooledNatsConn
	logger       *logrus.Logger
	group        *singleflight.Group
	natsDefaults *natsContextDefaults
	natsOpts     []nats.Option
}

func newNatsConnPool(logger *logrus.Logger, natsDefaults *natsContextDefaults, natsOpts []nats.Option) *natsConnPool {
	return &natsConnPool{
		cache:        map[string]*pooledNatsConn{},
		group:        &singleflight.Group{},
		logger:       logger,
		natsDefaults: natsDefaults,
		natsOpts:     natsOpts,
	}
}

const getPooledConnMaxTries = 10

// Get returns a *pooledNatsConn
func (cp *natsConnPool) Get(cfg *natsContext) (*pooledNatsConn, error) {
	if cfg == nil {
		return nil, fmt.Errorf("nats context must not be nil")
	}

	// copy cfg
	cfg = cfg.copy()

	// set defaults
	if cfg.Name == "" {
		cfg.Name = cp.natsDefaults.Name
	}
	if cfg.URL == "" {
		cfg.URL = cp.natsDefaults.URL
	}
	if len(cfg.TLSCAs) == 0 {
		cfg.TLSCAs = cp.natsDefaults.TLSCAs
	}
	if cfg.TLSCert == "" {
		cfg.TLSCert = cp.natsDefaults.TLSCert
	}
	if cfg.TLSKey == "" {
		cfg.TLSKey = cp.natsDefaults.TLSKey
	}

	// get hash
	key, err := cfg.hash()
	if err != nil {
		return nil, err
	}

	for i := 0; i < getPooledConnMaxTries; i++ {
		connection, err := cp.getPooledConn(key, cfg)
		if err != nil {
			return nil, err
		}

		cp.Lock()
		if connection.closed {
			// ReturnToPool closed this while lock not held, try again
			cp.Unlock()
			continue
		}

		// increment count out of the pool
		connection.count++
		cp.Unlock()
		return connection, nil
	}

	return nil, fmt.Errorf("failed to get pooled connection after %d attempts", getPooledConnMaxTries)
}

// getPooledConn gets or establishes a *pooledNatsConn in a singleflight group, but does not increment its count
func (cp *natsConnPool) getPooledConn(key string, cfg *natsContext) (*pooledNatsConn, error) {
	conn, err, _ := cp.group.Do(key, func() (interface{}, error) {
		cp.Lock()
		pooledConn, ok := cp.cache[key]
		if ok && pooledConn.nc.IsConnected() {
			cp.Unlock()
			return pooledConn, nil
		}
		cp.Unlock()

		opts := cp.natsOpts
		opts = append(opts, func(options *nats.Options) error {
			if cfg.Name != "" {
				options.Name = cfg.Name
			}
			if cfg.Token != "" {
				options.Token = cfg.Token
			}
			if cfg.Username != "" {
				options.User = cfg.Username
			}
			if cfg.Password != "" {
				options.Password = cfg.Password
			}
			return nil
		})

		if cfg.JWT != "" && cfg.Seed != "" {
			opts = append(opts, nats.UserJWTAndSeed(cfg.JWT, cfg.Seed))
		}

		if cfg.Nkey != "" {
			opt, err := nats.NkeyOptionFromSeed(cfg.Nkey)
			if err != nil {
				return nil, fmt.Errorf("unable to load nkey: %v", err)
			}
			opts = append(opts, opt)
		}

		if cfg.Credentials != "" {
			opts = append(opts, nats.UserCredentials(cfg.Credentials))
		}

		if len(cfg.TLSCAs) > 0 {
			opts = append(opts, nats.RootCAs(cfg.TLSCAs...))
		}

		if cfg.TLSCert != "" && cfg.TLSKey != "" {
			opts = append(opts, nats.ClientCert(cfg.TLSCert, cfg.TLSKey))
		}

		nc, err := nats.Connect(cfg.URL, opts...)
		if err != nil {
			return nil, err
		}
		cp.logger.Infof("%s connected to NATS Deployment: %s", cfg.Name, nc.ConnectedAddr())

		connection := &pooledNatsConn{
			nc:  nc,
			cp:  cp,
			key: key,
		}

		cp.Lock()
		cp.cache[key] = connection
		cp.Unlock()

		return connection, err
	})

	if err != nil {
		return nil, err
	}

	connection, ok := conn.(*pooledNatsConn)
	if !ok {
		return nil, fmt.Errorf("not a pooledNatsConn")
	}
	return connection, nil
}


================================================
FILE: controllers/jetstream/conn_pool_test.go
================================================
package jetstream

import (
	"sync"
	"testing"
	"time"

	"github.com/nats-io/nats.go"

	natsservertest "github.com/nats-io/nats-server/v2/test"
	"github.com/sirupsen/logrus"
	testifyAssert "github.com/stretchr/testify/assert"
)

func TestConnPool(t *testing.T) {
	t.Parallel()

	s := natsservertest.RunRandClientPortServer()
	defer s.Shutdown()
	o1 := &natsContext{
		Name: "Client 1",
	}
	o2 := &natsContext{
		Name: "Client 1",
	}
	o3 := &natsContext{
		Name: "Client 2",
	}

	natsDefaults := &natsContextDefaults{
		URL: s.ClientURL(),
	}
	natsOptions := []nats.Option{
		nats.MaxReconnects(10240),
	}
	cp := newNatsConnPool(logrus.New(), natsDefaults, natsOptions)

	var c1, c2, c3 *pooledNatsConn
	var c1e, c2e, c3e error
	wg := &sync.WaitGroup{}
	wg.Add(3)
	go func() {
		c1, c1e = cp.Get(o1)
		wg.Done()
	}()
	go func() {
		c2, c2e = cp.Get(o2)
		wg.Done()
	}()
	go func() {
		c3, c3e = cp.Get(o3)
		wg.Done()
	}()
	wg.Wait()

	assert := testifyAssert.New(t)
	if assert.NoError(c1e) && assert.NoError(c2e) {
		assert.Same(c1, c2)
	}
	if assert.NoError(c3e) {
		assert.NotSame(c1, c3)
		assert.NotSame(c2, c3)
	}

	c1.ReturnToPool()
	c3.ReturnToPool()
	time.Sleep(1 * time.Second)
	assert.False(c1.nc.IsClosed())
	assert.False(c2.nc.IsClosed())
	assert.True(c3.nc.IsClosed())

	c4, c4e := cp.Get(o1)
	if assert.NoError(c4e) {
		assert.Same(c2, c4)
	}

	c2.ReturnToPool()
	c4.ReturnToPool()
	time.Sleep(1 * time.Second)
	assert.True(c1.nc.IsClosed())
	assert.True(c2.nc.IsClosed())
	assert.True(c4.nc.IsClosed())

	c5, c5e := cp.Get(o1)
	if assert.NoError(c5e) {
		assert.NotSame(c1, c5)
	}

	c5.ReturnToPool()
	time.Sleep(1 * time.Second)
	assert.True(c5.nc.IsClosed())
}


================================================
FILE: controllers/jetstream/consumer.go
================================================
package jetstream

import (
	"context"
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/nats-io/jsm.go"
	jsmapi "github.com/nats-io/jsm.go/api"
	apis "github.com/nats-io/nack/pkg/jetstream/apis/jetstream/v1beta2"
	typed "github.com/nats-io/nack/pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2"
	k8sapi "k8s.io/api/core/v1"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/util/retry"
	klog "k8s.io/klog/v2"
)

func (c *Controller) runConsumerQueue() {
	for {
		processQueueNext(c.cnsQueue, c.RealJSMC, c.processConsumer)
	}
}

func (c *Controller) processConsumer(ns, name string, jsmClient jsmClientFunc) (err error) {
	cns, err := c.cnsLister.Consumers(ns).Get(name)
	if err != nil && k8serrors.IsNotFound(err) {
		return nil
	} else if err != nil {
		return err
	}

	return c.processConsumerObject(cns, jsmClient)
}

func (c *Controller) processConsumerObject(cns *apis.Consumer, jsm jsmClientFunc) (err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("failed to process consumer: %w", err)
		}
	}()

	ns := cns.Namespace
	spec := cns.Spec
	ifc := c.ji.Consumers(ns)

	acc, err := c.getAccountOverrides(spec.Account, ns)
	if err != nil {
		return err
	}

	defer func() {
		if err == nil {
			return
		}

		if _, serr := setConsumerErrored(c.ctx, cns, ifc, err); serr != nil {
			err = fmt.Errorf("%s: %w", err, serr)
		}
	}()

	type operator func(ctx context.Context, c jsmClient, spec apis.ConsumerSpec) (err error)

	natsClientUtil := func(op operator) error {
		return c.runWithJsmc(jsm, acc, &jsmcSpecOverrides{
			servers: spec.Servers,
			tls:     spec.TLS,
			creds:   spec.Creds,
			nkey:    spec.Nkey,
		}, cns, func(jsmc jsmClient) error {
			return op(c.ctx, jsmc, spec)
		})
	}

	deleteOK := cns.GetDeletionTimestamp() != nil
	newGeneration := cns.Generation != cns.Status.ObservedGeneration
	consumerOK := true
	err = natsClientUtil(consumerExists)
	var apierr jsmapi.ApiError
	if errors.As(err, &apierr) && apierr.NotFoundError() {
		consumerOK = false
	} else if err != nil {
		return err
	}
	updateOK := (consumerOK && !deleteOK && newGeneration)
	createOK := (!consumerOK && !deleteOK) || (!updateOK && !deleteOK && newGeneration)

	switch {
	case createOK:
		c.normalEvent(cns, "Creating",
			fmt.Sprintf("Creating consumer %q on stream %q", spec.DurableName, spec.StreamName))
		if err := natsClientUtil(createConsumer); err != nil {
			return err
		}

		if _, err := setConsumerOK(c.ctx, cns, ifc); err != nil {
			return err
		}
		c.normalEvent(cns, "Created",
			fmt.Sprintf("Created consumer %q on stream %q", spec.DurableName, spec.StreamName))
	case updateOK:
		if cns.Spec.PreventUpdate {
			c.normalEvent(cns, "SkipUpdate", fmt.Sprintf("Skip updating consumer %q on stream %q", spec.DurableName, spec.StreamName))
			if _, err := setConsumerOK(c.ctx, cns, ifc); err != nil {
				return err
			}
			return nil
		}
		c.normalEvent(cns, "Updating", fmt.Sprintf("Updating consumer %q on stream %q", spec.DurableName, spec.StreamName))
		if err := natsClientUtil(updateConsumer); err != nil {
			return err
		}

		if _, err := setConsumerOK(c.ctx, cns, ifc); err != nil {
			return err
		}
		c.normalEvent(cns, "Updated", fmt.Sprintf("Updated consumer %q on stream %q", spec.DurableName, spec.StreamName))
	case deleteOK:
		if cns.Spec.PreventDelete {
			c.normalEvent(cns, "SkipDelete", fmt.Sprintf("Skip deleting consumer %q on stream %q", spec.DurableName, spec.StreamName))
			if _, err := setConsumerOK(c.ctx, cns, ifc); err != nil {
				return err
			}
			return nil
		}
		c.normalEvent(cns, "Deleting", fmt.Sprintf("Deleting consumer %q on stream %q", spec.DurableName, spec.StreamName))
		if err := natsClientUtil(deleteConsumer); err != nil {
			return err
		}
	default:
		c.normalEvent(cns, "Noop", fmt.Sprintf("Nothing done for consumer %q (prevent-delete=%v, prevent-update=%v)",
			spec.DurableName, spec.PreventDelete, spec.PreventUpdate,
		))
		if _, err := setConsumerOK(c.ctx, cns, ifc); err != nil {
			return err
		}
	}

	return nil
}

func consumerExists(ctx context.Context, c jsmClient, spec apis.ConsumerSpec) (err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("failed to check if consumer exists: %w", err)
		}
	}()

	_, err = c.LoadConsumer(ctx, spec.StreamName, spec.DurableName)
	return err
}

func createConsumer(ctx context.Context, c jsmClient, spec apis.ConsumerSpec) (err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("failed to create consumer %q on stream %q: %w", spec.DurableName, spec.StreamName, err)
		}
	}()

	opts, err := consumerSpecToOpts(spec)
	if err != nil {
		return
	}
	_, err = c.NewConsumer(ctx, spec.StreamName, opts)
	return
}

func updateConsumer(ctx context.Context, c jsmClient, spec apis.ConsumerSpec) (err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("failed to update consumer %q on stream %q: %w", spec.DurableName, spec.StreamName, err)
		}
	}()

	js, err := c.LoadConsumer(ctx, spec.StreamName, spec.DurableName)
	if err != nil {
		return
	}

	opts, err := consumerSpecToOpts(spec)
	if err != nil {
		return
	}

	err = js.UpdateConfiguration(opts...)
	return
}

func consumerSpecToOpts(spec apis.ConsumerSpec) ([]jsm.ConsumerOption, error) {
	opts := []jsm.ConsumerOption{
		jsm.DurableName(spec.DurableName),
		jsm.DeliverySubject(spec.DeliverSubject),
		jsm.RateLimitBitsPerSecond(uint64(spec.RateLimitBps)),
		jsm.MaxAckPending(uint(spec.MaxAckPending)),
		jsm.ConsumerDescription(spec.Description),
		jsm.DeliverGroup(spec.DeliverGroup),
		jsm.MaxWaiting(uint(spec.MaxWaiting)),
		jsm.MaxRequestBatch(uint(spec.MaxRequestBatch)),
		jsm.MaxRequestMaxBytes(spec.MaxRequestMaxBytes),
		jsm.ConsumerOverrideReplicas(spec.Replicas),
	}

	if spec.FilterSubject != "" && len(spec.FilterSubjects) > 0 {
		return nil, fmt.Errorf("cannot specify both FilterSubject and FilterSubjects")
	}

	if spec.FilterSubject != "" {
		opts = append(opts, jsm.FilterStreamBySubject(spec.FilterSubject))
	} else if len(spec.FilterSubjects) > 0 {
		opts = append(opts, jsm.FilterStreamBySubject(spec.FilterSubjects...))
	}

	switch spec.DeliverPolicy {
	case "all":
		opts = append(opts, jsm.DeliverAllAvailable())
	case "last":
		opts = append(opts, jsm.StartWithLastReceived())
	case "new":
		opts = append(opts, jsm.StartWithNextReceived())
	case "byStartSequence":
		opts = append(opts, jsm.StartAtSequence(uint64(spec.OptStartSeq)))
	case "byStartTime":
		if spec.OptStartTime == "" {
			return nil, fmt.Errorf("'optStartTime' is required for deliver policy 'byStartTime'")
		}
		t, err := time.Parse(time.RFC3339, spec.OptStartTime)
		if err != nil {
			return nil, err
		}
		opts = append(opts, jsm.StartAtTime(t))
	case "lastPerSubject":
		opts = append(opts, jsm.DeliverLastPerSubject())
	case "":
	default:
		return nil, fmt.Errorf("invalid value for 'deliverPolicy': '%s'. Must be one of 'all', 'last', 'new', 'lastPerSubject', 'byStartSequence', 'byStartTime'", spec.DeliverPolicy)
	}

	switch spec.AckPolicy {
	case "none":
		opts = append(opts, jsm.AcknowledgeNone())
	case "all":
		opts = append(opts, jsm.AcknowledgeAll())
	case "explicit":
		opts = append(opts, jsm.AcknowledgeExplicit())
	case "":
	default:
		return nil, fmt.Errorf("invalid value for 'ackPolicy': '%s'. Must be one of 'none', 'all', 'explicit'", spec.AckPolicy)
	}

	if spec.AckWait != "" {
		d, err := time.ParseDuration(spec.AckWait)
		if err != nil {
			return nil, err
		}
		opts = append(opts, jsm.AckWait(d))
	}

	switch spec.ReplayPolicy {
	case "instant":
		opts = append(opts, jsm.ReplayInstantly())
	case "original":
		opts = append(opts, jsm.ReplayAsReceived())
	case "":
	default:
		return nil, fmt.Errorf("invalid value for 'replayPolicy': '%s'. Must be one of 'instant', 'original'", spec.ReplayPolicy)
	}

	if spec.SampleFreq != "" {
		n, err := strconv.Atoi(spec.SampleFreq)
		if err != nil {
			return nil, err
		}
		opts = append(opts, jsm.SamplePercent(n))
	}

	if spec.FlowControl {
		opts = append(opts, jsm.PushFlowControl())
	}

	if spec.HeartbeatInterval != "" {
		d, err := time.ParseDuration(spec.HeartbeatInterval)
		if err != nil {
			return nil, err
		}
		opts = append(opts, jsm.IdleHeartbeat(d))
	}

	if len(spec.BackOff) > 0 {
		backoffs := make([]time.Duration, 0)
		for _, backoff := range spec.BackOff {
			dur, err := time.ParseDuration(backoff)
			if err != nil {
				return nil, err
			}
			backoffs = append(backoffs, dur)
		}
		opts = append(opts, jsm.BackoffIntervals(backoffs...))
	}

	if spec.HeadersOnly {
		opts = append(opts, jsm.DeliverHeadersOnly())
	} else {
		opts = append(opts, jsm.DeliverBodies())
	}

	if spec.MaxRequestExpires != "" {
		dur, err := time.ParseDuration(spec.MaxRequestExpires)
		if err != nil {
			return nil, err
		}
		opts = append(opts, jsm.MaxRequestExpires(dur))
	}

	if spec.MemStorage {
		opts = append(opts, jsm.ConsumerOverrideMemoryStorage())
	}

	if spec.MaxDeliver != 0 {
		opts = append(opts, jsm.MaxDeliveryAttempts(spec.MaxDeliver))
	}

	if spec.Metadata != nil {
		opts = append(opts, jsm.ConsumerMetadata(spec.Metadata))
	}

	if spec.InactiveThreshold != "" {
		dur, err := time.ParseDuration(spec.InactiveThreshold)
		if err != nil {
			return nil, err
		}
		opts = append(opts, jsm.InactiveThreshold(dur))
	}

	// Handle PauseUntil for pausing consumer
	if spec.PauseUntil != "" {
		t, err := time.Parse(time.RFC3339, spec.PauseUntil)
		if err != nil {
			return nil, fmt.Errorf("invalid pauseUntil time: %w", err)
		}
		opts = append(opts, jsm.PauseUntil(t))
	}

	// Handle PriorityPolicy with PriorityGroups and PinnedTTL
	switch spec.PriorityPolicy {
	case "", "none":
		// Default is none, no need to set
	case "pinned_client":
		if spec.PinnedTTL != "" {
			dur, err := time.ParseDuration(spec.PinnedTTL)
			if err != nil {
				return nil, fmt.Errorf("invalid pinnedTTL duration: %w", err)
			}
			opts = append(opts, jsm.PinnedClientPriorityGroups(dur, spec.PriorityGroups...))
		}
	case "overflow":
		opts = append(opts, jsm.OverflowPriorityGroups(spec.PriorityGroups...))
	case "prioritized":
		opts = append(opts, jsm.PrioritizedPriorityGroups(spec.PriorityGroups...))
	default:
		return nil, fmt.Errorf("invalid priority policy: %s", spec.PriorityPolicy)
	}

	return opts, nil
}

func deleteConsumer(ctx context.Context, c jsmClient, spec apis.ConsumerSpec) (err error) {
	stream, consumer := spec.StreamName, spec.DurableName
	defer func() {
		if err != nil {
			err = fmt.Errorf("failed to delete consumer %q on stream %q: %w", consumer, stream, err)
		}
	}()

	if spec.PreventDelete {
		klog.Infof("Consumer %q is configured to preventDelete on stream %q:", stream, consumer)
		return nil
	}

	var apierr jsmapi.ApiError
	cn, err := c.LoadConsumer(ctx, stream, consumer)
	if errors.As(err, &apierr) && apierr.NotFoundError() {
		return nil
	} else if err != nil {
		return err
	}

	return cn.Delete()
}

func setConsumerOK(ctx context.Context, s *apis.Consumer, i typed.ConsumerInterface) (*apis.Consumer, error) {
	sc := s.DeepCopy()

	sc.Status.ObservedGeneration = s.Generation
	sc.Status.Conditions = UpsertCondition(sc.Status.Conditions, apis.Condition{
		Type:               readyCondType,
		Status:             k8sapi.ConditionTrue,
		LastTransitionTime: time.Now().UTC().Format(time.RFC3339Nano),
		Reason:             "Created",
		Message:            "Consumer successfully created",
	})

	var res *apis.Consumer
	err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
		var err error
		ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
		defer cancel()
		res, err = i.UpdateStatus(ctx, sc, k8smeta.UpdateOptions{})
		if err != nil {
			return fmt.Errorf("failed to set consumer %q status: %w", s.Spec.DurableName, err)
		}
		return nil
	})
	return res, err
}

func setConsumerErrored(ctx context.Context, s *apis.Consumer, sif typed.ConsumerInterface, err error) (*apis.Consumer, error) {
	if err == nil {
		return s, nil
	}

	sc := s.DeepCopy()
	sc.Status.Conditions = UpsertCondition(sc.Status.Conditions, apis.Condition{
		Type:               readyCondType,
		Status:             k8sapi.ConditionFalse,
		LastTransitionTime: time.Now().UTC().Format(time.RFC3339Nano),
		Reason:             "Errored",
		Message:            err.Error(),
	})

	var res *apis.Consumer
	err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
		var err error
		ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
		defer cancel()
		res, err = sif.UpdateStatus(ctx, sc, k8smeta.UpdateOptions{})
		if err != nil {
			return fmt.Errorf("failed to set consumer errored status: %w", err)
		}
		return nil
	})
	return res, err
}


================================================
FILE: controllers/jetstream/consumer_test.go
================================================
package jetstream

import (
	"context"
	"errors"
	"strings"
	"testing"
	"time"

	jsmapi "github.com/nats-io/jsm.go/api"
	apis "github.com/nats-io/nack/pkg/jetstream/apis/jetstream/v1beta2"
	clientsetfake "github.com/nats-io/nack/pkg/jetstream/generated/clientset/versioned/fake"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	k8sclientsetfake "k8s.io/client-go/kubernetes/fake"
	k8stesting "k8s.io/client-go/testing"
	"k8s.io/client-go/tools/record"
)

func TestProcessConsumer(t *testing.T) {
	t.Parallel()

	updateObject := func(a k8stesting.Action) (handled bool, o runtime.Object, err error) {
		ua, ok := a.(k8stesting.UpdateAction)
		if !ok {
			return false, nil, nil
		}

		return true, ua.GetObject(), nil
	}

	t.Run("create consumer", func(t *testing.T) {
		t.Parallel()

		jc := clientsetfake.NewSimpleClientset()
		wantEvents := 2
		rec := record.NewFakeRecorder(wantEvents)
		ctrl := NewController(Options{
			Ctx:            context.Background(),
			KubeIface:      k8sclientsetfake.NewSimpleClientset(),
			JetstreamIface: jc,
			Recorder:       rec,
		})

		ns, name := "default", "my-consumer"

		informer := ctrl.informerFactory.Jetstream().V1beta2().Consumers()
		err := informer.Informer().GetStore().Add(&apis.Consumer{
			ObjectMeta: k8smeta.ObjectMeta{
				Namespace:  ns,
				Name:       name,
				Generation: 1,
			},
			Spec: apis.ConsumerSpec{
				DurableName:       name,
				DeliverPolicy:     "byStartTime",
				OptStartTime:      time.Now().Format(time.RFC3339),
				AckPolicy:         "explicit",
				AckWait:           "1m",
				ReplayPolicy:      "original",
				SampleFreq:        "50",
				HeartbeatInterval: "30s",
				BackOff:           []string{"500ms", "1s"},
				HeadersOnly:       true,
				MaxRequestExpires: "5m",
				MemStorage:        true,
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		jc.PrependReactor("update", "consumers", updateObject)

		notFoundErr := jsmapi.ApiError{Code: 404}
		jsmc := &mockJsmClient{
			loadConsumerErr: notFoundErr,
			newConsumerErr:  nil,
			newConsumer:     &mockConsumer{},
		}
		if err := ctrl.processConsumer(ns, name, func(n *natsContext) (jsmClient, error) {
			return jsmc, nil
		}); err != nil {
			t.Fatal(err)
		}

		if got := len(rec.Events); got != wantEvents {
			t.Error("unexpected number of events")
			t.Fatalf("got=%d; want=%d", got, wantEvents)
		}

		for i := 0; i < len(rec.Events); i++ {
			gotEvent := <-rec.Events
			if !strings.Contains(gotEvent, "Creat") {
				t.Error("unexpected event")
				t.Fatalf("got=%s; want=%s", gotEvent, "Creating/Created...")
			}
		}
	})

	t.Run("create consumer, invalid configuration", func(t *testing.T) {
		t.Parallel()

		jc := clientsetfake.NewSimpleClientset()
		wantEvents := 1
		rec := record.NewFakeRecorder(wantEvents)
		ctrl := NewController(Options{
			Ctx:            context.Background(),
			KubeIface:      k8sclientsetfake.NewSimpleClientset(),
			JetstreamIface: jc,
			Recorder:       rec,
		})

		ns, name := "default", "my-consumer"

		informer := ctrl.informerFactory.Jetstream().V1beta2().Consumers()
		err := informer.Informer().GetStore().Add(&apis.Consumer{
			ObjectMeta: k8smeta.ObjectMeta{
				Namespace:  ns,
				Name:       name,
				Generation: 1,
			},
			Spec: apis.ConsumerSpec{
				DurableName:   name,
				DeliverPolicy: "invalid",
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		jc.PrependReactor("update", "consumers", updateObject)

		notFoundErr := jsmapi.ApiError{Code: 404}
		jsmc := &mockJsmClient{
			loadConsumerErr: notFoundErr,
			newConsumerErr:  nil,
			newConsumer:     &mockConsumer{},
		}
		if err := ctrl.processConsumer(ns, name, testWrapJSMC(jsmc)); err == nil || !strings.Contains(err.Error(), `failed to create consumer "my-consumer" on stream `) {
			t.Fatal(err)
		}

		if got := len(rec.Events); got != wantEvents {
			t.Error("unexpected number of events")
			t.Fatalf("got=%d; want=%d", got, wantEvents)
		}

		gotEvent := <-rec.Events
		if !strings.Contains(gotEvent, "Creating") {
			t.Error("unexpected event")
			t.Fatalf("got=%s; want=%s", gotEvent, "Creating...")
		}
	})

	t.Run("update consumer", func(t *testing.T) {
		t.Parallel()

		jc := clientsetfake.NewSimpleClientset()
		wantEvents := 2
		rec := record.NewFakeRecorder(wantEvents)
		ctrl := NewController(Options{
			Ctx:            context.Background(),
			KubeIface:      k8sclientsetfake.NewSimpleClientset(),
			JetstreamIface: jc,
			Recorder:       rec,
		})

		ns, name := "default", "my-consumer"

		informer := ctrl.informerFactory.Jetstream().V1beta2().Consumers()
		err := informer.Informer().GetStore().Add(&apis.Consumer{
			ObjectMeta: k8smeta.ObjectMeta{
				Namespace:  ns,
				Name:       name,
				Generation: 2,
			},
			Spec: apis.ConsumerSpec{
				DurableName: name,
			},
			Status: apis.Status{
				ObservedGeneration: 1,
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		jc.PrependReactor("update", "consumers", updateObject)

		jsmc := &mockJsmClient{
			loadConsumerErr: nil,
			loadConsumer:    &mockConsumer{},
		}
		if err := ctrl.processConsumer(ns, name, testWrapJSMC(jsmc)); err != nil {
			t.Fatal(err)
		}

		if got := len(rec.Events); got != wantEvents {
			t.Error("unexpected number of events")
			t.Fatalf("got=%d; want=%d", got, wantEvents)
		}

		for i := 0; i < len(rec.Events); i++ {
			gotEvent := <-rec.Events
			if !strings.Contains(gotEvent, "Updat") {
				t.Error("unexpected event")
				t.Fatalf("got=%s; want=%s", gotEvent, "Updating/Updated...")
			}
		}
	})

	t.Run("delete consumer", func(t *testing.T) {
		t.Parallel()

		jc := clientsetfake.NewSimpleClientset()
		wantEvents := 1
		rec := record.NewFakeRecorder(wantEvents)
		ctrl := NewController(Options{
			Ctx:            context.Background(),
			KubeIface:      k8sclientsetfake.NewSimpleClientset(),
			JetstreamIface: jc,
			Recorder:       rec,
		})

		ts := k8smeta.Unix(1600216923, 0)
		ns, name := "default", "my-consumer"

		informer := ctrl.informerFactory.Jetstream().V1beta2().Consumers()
		err := informer.Informer().GetStore().Add(&apis.Consumer{
			ObjectMeta: k8smeta.ObjectMeta{
				Namespace:         ns,
				Name:              name,
				DeletionTimestamp: &ts,
			},
			Spec: apis.ConsumerSpec{
				DurableName: name,
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		jc.PrependReactor("update", "consumers", updateObject)

		jsmc := &mockJsmClient{
			loadConsumerErr: nil,
			loadConsumer:    &mockConsumer{},
		}
		if err := ctrl.processConsumer(ns, name, testWrapJSMC(jsmc)); err != nil {
			t.Fatal(err)
		}

		if got := len(rec.Events); got != wantEvents {
			t.Error("unexpected number of events")
			t.Fatalf("got=%d; want=%d", got, wantEvents)
		}

		gotEvent := <-rec.Events
		if !strings.Contains(gotEvent, "Deleting") {
			t.Error("unexpected event")
			t.Fatalf("got=%s; want=%s", gotEvent, "Deleting...")
		}
	})

	t.Run("process error", func(t *testing.T) {
		t.Parallel()

		jc := clientsetfake.NewSimpleClientset()
		wantEvents := 1
		rec := record.NewFakeRecorder(wantEvents)
		ctrl := NewController(Options{
			Ctx:            context.Background(),
			KubeIface:      k8sclientsetfake.NewSimpleClientset(),
			JetstreamIface: jc,
			Recorder:       rec,
		})

		ns, name := "default", "my-consumer"

		informer := ctrl.informerFactory.Jetstream().V1beta2().Consumers()
		err := informer.Informer().GetStore().Add(&apis.Consumer{
			ObjectMeta: k8smeta.ObjectMeta{
				Namespace:  ns,
				Name:       name,
				Generation: 1,
			},
			Spec: apis.ConsumerSpec{
				DurableName: name,
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		jc.PrependReactor("update", "consumers", func(a k8stesting.Action) (handled bool, o runtime.Object, err error) {
			ua, ok := a.(k8stesting.UpdateAction)
			if !ok {
				return false, nil, nil
			}
			obj := ua.GetObject()

			str, ok := obj.(*apis.Consumer)
			if !ok {
				t.Error("unexpected object type")
				t.Fatalf("got=%T; want=%T", obj, &apis.Consumer{})
			}

			if got, want := len(str.Status.Conditions), 1; got != want {
				t.Error("unexpected number of conditions")
				t.Fatalf("got=%d; want=%d", got, want)
			}
			if got, want := str.Status.Conditions[0].Reason, "Errored"; got != want {
				t.Error("unexpected condition reason")
				t.Fatalf("got=%s; want=%s", got, want)
			}

			return true, obj, nil
		})

		jsmc := &mockJsmClient{
			loadConsumerErr: errors.New("failed to load consumer"),
		}
		if err := ctrl.processConsumer(ns, name, testWrapJSMC(jsmc)); err == nil {
			t.Fatal("unexpected success")
		}
	})
}

func TestConsumerSpecToOpts(t *testing.T) {
	tests := map[string]struct {
		name     string
		given    apis.ConsumerSpec
		expected jsmapi.ConsumerConfig
		errCheck func(t *testing.T, err error)
	}{
		"valid consumer spec": {
			given: apis.ConsumerSpec{
				DurableName:       "my-consumer",
				DeliverPolicy:     "byStartSequence",
				OptStartSeq:       10,
				AckPolicy:         "explicit",
				AckWait:           "1m",
				ReplayPolicy:      "original",
				SampleFreq:        "50",
				HeartbeatInterval: "30s",
				BackOff:           []string{"500ms", "1s"},
				HeadersOnly:       true,
				MaxRequestExpires: "5m",
				MemStorage:        true,
			},
			expected: jsmapi.ConsumerConfig{
				AckPolicy:         jsmapi.AckExplicit,
				AckWait:           1 * time.Minute,
				DeliverPolicy:     jsmapi.DeliverByStartSequence,
				Durable:           "my-consumer",
				Heartbeat:         30 * time.Second,
				BackOff:           []time.Duration{500 * time.Millisecond, 1 * time.Second},
				OptStartSeq:       10,
				ReplayPolicy:      jsmapi.ReplayOriginal,
				SampleFrequency:   "50%",
				HeadersOnly:       true,
				MaxRequestExpires: 5 * time.Minute,
				MemoryStorage:     true,
			},
		},
		"valid consumer spec, defaults only": {
			given: apis.ConsumerSpec{
				DurableName: "my-consumer",
			},
			expected: jsmapi.ConsumerConfig{
				Durable: "my-consumer",
			},
		},
		"invalid deliver policy value": {
			given: apis.ConsumerSpec{
				DurableName:   "my-consumer",
				DeliverPolicy: "invalid",
			},
			errCheck: func(t *testing.T, err error) {
				require.Error(t, err)
				require.Contains(t, err.Error(), "invalid value for 'deliverPolicy': 'invalid'")
			},
		},
		"missing start time for deliver policy byStartTime": {
			given: apis.ConsumerSpec{
				DurableName:   "my-consumer",
				DeliverPolicy: "byStartTime",
			},
			errCheck: func(t *testing.T, err error) {
				require.Error(t, err)
				require.Contains(t, err.Error(), "'optStartTime' is required for deliver policy 'byStartTime'")
			},
		},
		"deliver policy lastPerSubject": {
			given: apis.ConsumerSpec{
				DurableName:   "my-consumer",
				DeliverPolicy: "lastPerSubject",
			},
			expected: jsmapi.ConsumerConfig{
				Durable:       "my-consumer",
				DeliverPolicy: jsmapi.DeliverLastPerSubject,
			},
		},
		"invalid ack policy": {
			given: apis.ConsumerSpec{
				DurableName: "my-consumer",
				AckPolicy:   "invalid",
			},
			errCheck: func(t *testing.T, err error) {
				require.Error(t, err)
				require.Contains(t, err.Error(), "invalid value for 'ackPolicy': 'invalid'")
			},
		},
		"invalid replay policy": {
			given: apis.ConsumerSpec{
				DurableName:  "my-consumer",
				ReplayPolicy: "invalid",
			},
			errCheck: func(t *testing.T, err error) {
				require.Error(t, err)
				require.Contains(t, err.Error(), "invalid value for 'replayPolicy': 'invalid'")
			},
		},
	}

	for name, test := range tests {
		t.Run(name, func(t *testing.T) {
			res, err := consumerSpecToOpts(test.given)
			if test.errCheck != nil {
				test.errCheck(t, err)
				return
			}
			require.NoError(t, err)
			var config jsmapi.ConsumerConfig
			for _, opt := range res {
				err := opt(&config)
				require.NoError(t, err)
			}
			assert.Equal(t, test.expected, config)
		})
	}
}

func testWrapJSMC(jsm jsmClient) jsmClientFunc {
	return func(n *natsContext) (jsmClient, error) {
		return jsm, nil
	}
}


================================================
FILE: controllers/jetstream/controller.go
================================================
// Copyright 2020-2022 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package jetstream

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/nats-io/jsm.go"
	jsmapi "github.com/nats-io/jsm.go/api"
	"github.com/nats-io/nats.go"
	"github.com/sirupsen/logrus"

	apis "github.com/nats-io/nack/pkg/jetstream/apis/jetstream/v1beta2"
	clientset "github.com/nats-io/nack/pkg/jetstream/generated/clientset/versioned"
	scheme "github.com/nats-io/nack/pkg/jetstream/generated/clientset/versioned/scheme"
	typed "github.com/nats-io/nack/pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2"
	informers "github.com/nats-io/nack/pkg/jetstream/generated/informers/externalversions"
	listers "github.com/nats-io/nack/pkg/jetstream/generated/listers/jetstream/v1beta2"

	k8sapi "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/equality"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes"
	k8sscheme "k8s.io/client-go/kubernetes/scheme"
	k8styped "k8s.io/client-go/kubernetes/typed/core/v1"
	_ "k8s.io/client-go/plugin/pkg/client/auth"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/workqueue"
	klog "k8s.io/klog/v2"
)

const (
	// maxQueueRetries is the max times an item will be retried. An item will
	// be pulled maxQueueRetries+1 times from the queue. On pull number
	// maxQueueRetries+1, if it fails again, it won't be retried.
	maxQueueRetries = 10

	// readyCondType is the Ready condition type.
	readyCondType = "Ready"
)

type Options struct {
	Ctx context.Context

	KubeIface      kubernetes.Interface
	JetstreamIface clientset.Interface

	NATSClientName  string
	NATSCredentials string
	NATSNKey        string
	NATSServerURL   string

	NATSCA          string
	NATSCertificate string
	NATSKey         string

	NATSTLSFirst bool

	Namespace     string
	CRDConnect    bool
	CleanupPeriod time.Duration
	ReadOnly      bool

	Recorder record.EventRecorder
}

type Controller struct {
	ctx      context.Context
	opts     Options
	connPool *natsConnPool

	ki              k8styped.CoreV1Interface
	ji              typed.JetstreamV1beta2Interface
	informerFactory informers.SharedInformerFactory
	rec             record.EventRecorder

	strLister listers.StreamLister
	strSynced cache.InformerSynced
	strQueue  workqueue.TypedRateLimitingInterface[any]

	cnsLister listers.ConsumerLister
	cnsSynced cache.InformerSynced
	cnsQueue  workqueue.TypedRateLimitingInterface[any]

	accLister listers.AccountLister

	// Informers for unsupported resources (KeyValue and ObjectStore)
	// These are only used to emit warnings in legacy mode
	kvLister listers.KeyValueLister
	kvSynced cache.InformerSynced

	osLister listers.ObjectStoreLister
	osSynced cache.InformerSynced

	// cacheDir is where the downloaded TLS certs from the server
	// will be stored temporarily.
	cacheDir string
}

func NewController(opt Options) *Controller {
	resyncPeriod := 30 * time.Second
	informerFactory := informers.NewSharedInformerFactoryWithOptions(opt.JetstreamIface, resyncPeriod, informers.WithNamespace(opt.Namespace))

	streamInformer := informerFactory.Jetstream().V1beta2().Streams()
	consumerInformer := informerFactory.Jetstream().V1beta2().Consumers()
	accountInformer := informerFactory.Jetstream().V1beta2().Accounts()
	keyValueInformer := informerFactory.Jetstream().V1beta2().KeyValues()
	objectStoreInformer := informerFactory.Jetstream().V1beta2().ObjectStores()

	if opt.Recorder == nil {
		utilruntime.Must(scheme.AddToScheme(k8sscheme.Scheme))
		eventBroadcaster := record.NewBroadcaster()
		eventBroadcaster.StartLogging(klog.Infof)
		eventBroadcaster.StartRecordingToSink(&k8styped.EventSinkImpl{
			Interface: opt.KubeIface.CoreV1().Events(""),
		})

		opt.Recorder = eventBroadcaster.NewRecorder(k8sscheme.Scheme, k8sapi.EventSource{
			Component: "jetstream-controller",
		})
	}

	if opt.NATSClientName == "" {
		opt.NATSClientName = "jetstream-controller"
	}

	ji := opt.JetstreamIface.JetstreamV1beta2()
	streamQueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultTypedControllerRateLimiter[any](), "Streams")
	consumerQueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultTypedControllerRateLimiter[any](), "Consumers")

	streamInformer.Informer().AddEventHandler(
		eventHandlers(
			streamQueue,
		),
	)

	consumerInformer.Informer().AddEventHandler(
		eventHandlers(
			consumerQueue,
		),
	)

	// Add warning handlers for unsupported resources in legacy mode
	keyValueInformer.Informer().AddEventHandler(
		cache.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				if kv, ok := obj.(*apis.KeyValue); ok {
					klog.Warningf("KeyValue resource %s/%s detected but not supported in legacy mode. The NATS KV bucket will NOT be created. Enable --control-loop mode to use KeyValue resources.", kv.Namespace, kv.Name)
					opt.Recorder.Event(kv, k8sapi.EventTypeWarning, "NotSupported", "KeyValue resources require --control-loop mode. The NATS KV bucket will NOT be created.")
				}
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				if kv, ok := newObj.(*apis.KeyValue); ok {
					klog.Warningf("KeyValue resource %s/%s updated but not supported in legacy mode. Changes will NOT be applied to NATS. Enable --control-loop mode to use KeyValue resources.", kv.Namespace, kv.Name)
					opt.Recorder.Event(kv, k8sapi.EventTypeWarning, "NotSupported", "KeyValue resources require --control-loop mode. Updates will NOT be applied.")
				}
			},
		},
	)

	objectStoreInformer.Informer().AddEventHandler(
		cache.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				if os, ok := obj.(*apis.ObjectStore); ok {
					klog.Warningf("ObjectStore resource %s/%s detected but not supported in legacy mode. The NATS object store will NOT be created. Enable --control-loop mode to use ObjectStore resources.", os.Namespace, os.Name)
					opt.Recorder.Event(os, k8sapi.EventTypeWarning, "NotSupported", "ObjectStore resources require --control-loop mode. The NATS object store will NOT be created.")
				}
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				if os, ok := newObj.(*apis.ObjectStore); ok {
					klog.Warningf("ObjectStore resource %s/%s updated but not supported in legacy mode. Changes will NOT be applied to NATS. Enable --control-loop mode to use ObjectStore resources.", os.Namespace, os.Name)
					opt.Recorder.Event(os, k8sapi.EventTypeWarning, "NotSupported", "ObjectStore resources require --control-loop mode. Updates will NOT be applied.")
				}
			},
		},
	)

	cacheDir, err := os.MkdirTemp(".", "nack")
	if err != nil {
		panic(err)
	}
	defer os.RemoveAll(cacheDir)

	return &Controller{
		ctx:  opt.Ctx,
		opts: opt,

		ki:              opt.KubeIface.CoreV1(),
		ji:              ji,
		informerFactory: informerFactory,
		rec:             opt.Recorder,

		strLister: streamInformer.Lister(),
		strSynced: streamInformer.Informer().HasSynced,
		strQueue:  streamQueue,

		cnsLister: consumerInformer.Lister(),
		cnsSynced: consumerInformer.Informer().HasSynced,
		cnsQueue:  consumerQueue,

		accLister: accountInformer.Lister(),

		kvLister: keyValueInformer.Lister(),
		kvSynced: keyValueInformer.Informer().HasSynced,

		osLister: objectStoreInformer.Lister(),
		osSynced: objectStoreInformer.Informer().HasSynced,

		cacheDir: cacheDir,
	}
}

func (c *Controller) Run() error {
	// Connect to NATS.
	opts := make([]nats.Option, 0)
	// Always attempt to have a connection to NATS.
	opts = append(opts, nats.MaxReconnects(-1))
	if c.opts.NATSTLSFirst {
		opts = append(opts, nats.TLSHandshakeFirst())
	}
	natsCtxDefaults := &natsContextDefaults{Name: c.opts.NATSClientName}
	if !c.opts.CRDConnect {
		// Use JWT/NKEYS based credentials if present.
		if c.opts.NATSCredentials != "" {
			opts = append(opts, nats.UserCredentials(c.opts.NATSCredentials))
		} else if c.opts.NATSNKey != "" {
			opt, err := nats.NkeyOptionFromSeed(c.opts.NATSNKey)
			if err != nil {
				return nil
			}
			opts = append(opts, opt)
		}

		if c.opts.NATSCertificate != "" && c.opts.NATSKey != "" {
			natsCtxDefaults.TLSCert = c.opts.NATSCertificate
			natsCtxDefaults.TLSKey = c.opts.NATSKey
		}

		if c.opts.NATSCA != "" {
			natsCtxDefaults.TLSCAs = []string{c.opts.NATSCA}
		}
		natsCtxDefaults.URL = c.opts.NATSServerURL
		ncp := newNatsConnPool(logrus.New(), natsCtxDefaults, opts)
		pooledNc, err := ncp.Get(&natsContext{})
		if err != nil {
			return fmt.Errorf("failed to connect to nats: %w", err)
		}
		pooledNc.ReturnToPool()
		c.connPool = ncp
	} else {
		c.connPool = newNatsConnPool(logrus.New(), natsCtxDefaults, opts)
	}

	defer utilruntime.HandleCrash()

	defer c.strQueue.ShutDown()
	defer c.cnsQueue.ShutDown()

	c.informerFactory.Start(c.ctx.Done())

	if !cache.WaitForCacheSync(c.ctx.Done(), c.strSynced) {
		return fmt.Errorf("failed to wait for stream cache sync")
	}
	if !cache.WaitForCacheSync(c.ctx.Done(), c.cnsSynced) {
		return fmt.Errorf("failed to wait for consumer cache sync")
	}
	// Also wait for KeyValue and ObjectStore caches to sync so we can emit warnings
	if !cache.WaitForCacheSync(c.ctx.Done(), c.kvSynced) {
		return fmt.Errorf("failed to wait for keyvalue cache sync")
	}
	if !cache.WaitForCacheSync(c.ctx.Done(), c.osSynced) {
		return fmt.Errorf("failed to wait for objectstore cache sync")
	}

	go wait.Until(c.runStreamQueue, time.Second, c.ctx.Done())
	go wait.Until(c.runConsumerQueue, time.Second, c.ctx.Done())
	go c.cleanupStreams()
	go c.cleanupConsumers()

	<-c.ctx.Done()

	// Gracefully shutdown.
	return nil
}

// RealJSMC creates a new JSM client from pooled nats connections
// Providing a blank string for servers, defaults to c.opts.NATSServerUrls
// call deferred jsmC.Close() on returned instance to return the nats connection to pool
func (c *Controller) RealJSMC(cfg *natsContext) (jsmClient, error) {
	if cfg == nil {
		cfg = &natsContext{}
	}
	pooledNc, err := c.connPool.Get(cfg)
	if err != nil {
		return nil, err
	}
	jm, err := jsm.New(pooledNc.nc)
	if err != nil {
		return nil, err
	}
	jsmc := &realJsmClient{pooledNc: pooledNc, jm: jm}
	return jsmc, nil
}

func selectMissingStreamsFromList(prev, cur map[string]*apis.Stream) []*apis.Stream {
	var deleted []*apis.Stream
	for name, ps := range prev {
		if _, ok := cur[name]; !ok {
			deleted = append(deleted, ps)
		}
	}
	return deleted
}

func streamsMap(ss []*apis.Stream) map[string]*apis.Stream {
	m := make(map[string]*apis.Stream)
	for _, s := range ss {
		m[fmt.Sprintf("%s/%s", s.Namespace, s.Name)] = s
	}
	return m
}

func (c *Controller) cleanupStreams() error {
	if c.opts.ReadOnly {
		return nil
	}
	tick := time.NewTicker(c.opts.CleanupPeriod)
	defer tick.Stop()

	// Track the Stream CRDs that may have been created.
	var prevStreams map[string]*apis.Stream
	for {
		select {
		case <-c.ctx.Done():
			return c.ctx.Err()
		case <-tick.C:
			streams, err := c.strLister.List(labels.Everything())
			if err != nil {
				klog.Infof("failed to list streams for cleanup: %s", err)
				continue
			}
			sm := streamsMap(streams)
			missing := selectMissingStreamsFromList(prevStreams, sm)
			for _, s := range missing {
				// A stream that we were tracking but that for some reason
				// was not part of the latest list shared by informer.
				// Need to double check whether the stream is present before
				// considering deletion.
				klog.Infof("stream %s/%s might be missing, looking it up...", s.Namespace, s.Name)
				ctx, done := context.WithTimeout(context.Background(), 10*time.Second)
				defer done()
				_, err := c.ji.Streams(s.Namespace).Get(ctx, s.Name, k8smeta.GetOptions{})
				if err != nil {
					if k8serrors.IsNotFound(err) {
						klog.Infof("stream %s/%s was not found anymore, deleting from JetStream", s.Namespace, s.Name)
						t := k8smeta.NewTime(time.Now())
						s.DeletionTimestamp = &t
						if err := c.processStreamObject(s, c.RealJSMC); err != nil && !k8serrors.IsNotFound(err) {
							klog.Infof("failed to delete stream %s/%s: %s", s.Namespace, s.Name, err)
							continue
						}
						klog.Infof("deleted stream %s/%s from JetStream", s.Namespace, s.Name)
					} else {
						klog.Warningf("error looking up stream %s/%s", s.Namespace, s.Name)
					}
				} else {
					klog.Infof("found stream %s/%s, no further action needed", s.Namespace, s.Name)
				}
			}
			prevStreams = sm
		}
	}
}

func selectMissingConsumersFromList(prev, cur map[string]*apis.Consumer) []*apis.Consumer {
	var deleted []*apis.Consumer
	for name, ps := range prev {
		if _, ok := cur[name]; !ok {
			deleted = append(deleted, ps)
		}
	}
	return deleted
}

func consumerMap(cs []*apis.Consumer) map[string]*apis.Consumer {
	m := make(map[string]*apis.Consumer)
	for _, c := range cs {
		m[fmt.Sprintf("%s/%s", c.Namespace, c.Name)] = c
	}
	return m
}

func (c *Controller) cleanupConsumers() error {
	if c.opts.ReadOnly {
		return nil
	}
	tick := time.NewTicker(c.opts.CleanupPeriod)
	defer tick.Stop()

	// Track consumers that may have been deleted.
	var prevConsumers map[string]*apis.Consumer
	for {
		select {
		case <-c.ctx.Done():
			return c.ctx.Err()
		case <-tick.C:
			consumers, err := c.cnsLister.List(labels.Everything())
			if err != nil {
				klog.Infof("failed to list consumers for cleanup: %s", err)
				continue
			}
			cm := consumerMap(consumers)
			missing := selectMissingConsumersFromList(prevConsumers, cm)
			for _, cns := range missing {
				// A consumer that we were tracking but that for some reason
				// was not part of the latest list shared by informer.
				// Need to double check whether the consumer is present before
				// considering deletion.
				klog.Infof("consumer %s/%s might be missing, looking it up...", cns.Namespace, cns.Name)
				ctx, done := context.WithTimeout(context.Background(), 10*time.Second)
				defer done()
				_, err := c.ji.Consumers(cns.Namespace).Get(ctx, cns.Name, k8smeta.GetOptions{})
				if err != nil {
					if k8serrors.IsNotFound(err) {
						klog.Infof("consumer %s/%s was not found anymore, deleting from JetStream", cns.Namespace, cns.Name)
						t := k8smeta.NewTime(time.Now())
						cns.DeletionTimestamp = &t
						if err := c.processConsumerObject(cns, c.RealJSMC); err != nil && !k8serrors.IsNotFound(err) {
							klog.Infof("failed to delete consumer %s/%s: %s", cns.Namespace, cns.Name, err)
							continue
						}
						klog.Infof("deleted consumer %s/%s from JetStream", cns.Namespace, cns.Name)
					} else {
						klog.Warningf("error looking up consumer %s/%s", cns.Namespace, cns.Name)
					}
				} else {
					klog.Infof("found consumer %s/%s, no further action needed", cns.Namespace, cns.Name)
				}
			}
			prevConsumers = cm
		}
	}
}

func (c *Controller) normalEvent(o runtime.Object, reason, message string) {
	if c.rec != nil {
		c.rec.Event(o, k8sapi.EventTypeNormal, reason, message)
	}
}

func (c *Controller) warningEvent(o runtime.Object, reason, message string) {
	if c.rec != nil {
		c.rec.Event(o, k8sapi.EventTypeWarning, reason, message)
	}
}

type accountOverrides struct {
	remoteClientCert string
	remoteClientKey  string
	remoteRootCA     string
	servers          []string
	userCreds        string
	nkey             string
	user             string
	password         string
	token            string
}

func (c *Controller) getAccountOverrides(account string, ns string) (*accountOverrides, error) {
	overrides := &accountOverrides{}

	if account == "" || !c.opts.CRDConnect {
		return overrides, nil
	}

	// Lookup the account using the REST client.
	ctx, done := context.WithTimeout(context.Background(), 5*time.Second)
	defer done()
	acc, err := c.ji.Accounts(ns).Get(ctx, account, k8smeta.GetOptions{})
	if err != nil {
		return nil, err
	}

	overrides.servers = acc.Spec.Servers

	// Lookup the TLS secrets
	if acc.Spec.TLS != nil && acc.Spec.TLS.Secret != nil {
		secretName := acc.Spec.TLS.Secret.Name
		secret, err := c.ki.Secrets(ns).Get(c.ctx, secretName, k8smeta.GetOptions{})
		if err != nil {
			return nil, err
		}

		// Write this to the cacheDir.
		accDir := filepath.Join(c.cacheDir, ns, account)
		if err := os.MkdirAll(accDir, 0o755); err != nil {
			return nil, err
		}

		var certData, keyData []byte
		var certPath, keyPath string

		for k, v := range secret.Data {
			switch k {
			case acc.Spec.TLS.ClientCert:
				certPath = filepath.Join(accDir, k)
				certData = v
			case acc.Spec.TLS.ClientKey:
				keyPath = filepath.Join(accDir, k)
				keyData = v
			case acc.Spec.TLS.RootCAs:
				overrides.remoteRootCA = filepath.Join(accDir, k)
				if err := os.WriteFile(overrides.remoteRootCA, v, 0o644); err != nil {
					return nil, err
				}
			}
		}

		if certData != nil && keyData != nil {
			overrides.remoteClientCert = certPath
			overrides.remoteClientKey = keyPath

			if err := os.WriteFile(certPath, certData, 0o644); err != nil {
				return nil, err
			}
			if err := os.WriteFile(keyPath, keyData, 0o644); err != nil {
				return nil, err
			}
		}
	}

	// Lookup the UserCredentials.
	if acc.Spec.Creds != nil && acc.Spec.Creds.Secret != nil {
		secretName := acc.Spec.Creds.Secret.Name
		secret, err := c.ki.Secrets(ns).Get(c.ctx, secretName, k8smeta.GetOptions{})
		if err != nil {
			return nil, err
		}

		// Write the user credentials to the cache dir.
		accDir := filepath.Join(c.cacheDir, ns, account)
		if err := os.MkdirAll(accDir, 0o755); err != nil {
			return nil, err
		}

		if credsBytes, ok := secret.Data[acc.Spec.Creds.File]; ok {
			overrides.userCreds = filepath.Join(accDir, acc.Spec.Creds.File)
			if err := os.WriteFile(overrides.userCreds, credsBytes, 0o644); err != nil {
				return nil, err
			}
		}
	}

	// Lookup the NKey seed.
	if acc.Spec.NKey != nil && acc.Spec.NKey.Secret != nil {
		secretName := acc.Spec.NKey.Secret.Name
		secret, err := c.ki.Secrets(ns).Get(c.ctx, secretName, k8smeta.GetOptions{})
		if err != nil {
			return nil, err
		}

		if nkeyBytes, ok := secret.Data[acc.Spec.NKey.Seed]; ok {
			overrides.nkey = string(nkeyBytes)
		}
	}

	// Lookup the Token.
	if acc.Spec.Token != nil {
		secretName := acc.Spec.Token.Secret.Name
		secret, err := c.ki.Secrets(ns).Get(c.ctx, secretName, k8smeta.GetOptions{})
		if err != nil {
			return nil, err
		}

		if token, ok := secret.Data[acc.Spec.Token.Token]; ok {
			overrides.token = string(token)
		}
	}

	// Lookup the User.
	if acc.Spec.User != nil {
		secretName := acc.Spec.User.Secret.Name
		secret, err := c.ki.Secrets(ns).Get(c.ctx, secretName, k8smeta.GetOptions{})
		if err != nil {
			return nil, err
		}

		userBytes := secret.Data[acc.Spec.User.User]
		passwordBytes := secret.Data[acc.Spec.User.Password]
		if userBytes != nil && passwordBytes != nil {
			overrides.user = string(userBytes)
			overrides.password = string(passwordBytes)
		}
	}

	return overrides, nil
}

type jsmcSpecOverrides struct {
	servers []string
	tls     *apis.TLS
	creds   string
	nkey    string
}

func (c *Controller) runWithJsmc(jsm jsmClientFunc, acc *accountOverrides, spec *jsmcSpecOverrides, o runtime.Object, op func(jsmClient) error) error {
	if !c.opts.CRDConnect {
		jsmc, err := jsm(&natsContext{})
		if err != nil {
			return err
		}

		return op(jsmc)
	}

	// Create a new client
	natsCtx := &natsContext{}
	// Use JWT/NKEYS/user-password/token based credentials if present.
	if spec.creds != "" {
		natsCtx.Credentials = spec.creds
	} else if spec.nkey != "" {
		natsCtx.Nkey = spec.nkey
	}
	if spec.tls != nil {
		if spec.tls.ClientCert != "" && spec.tls.ClientKey != "" {
			natsCtx.TLSCert = spec.tls.ClientCert
			natsCtx.TLSKey = spec.tls.ClientKey
		}
	}

	// Use fetched secrets for the account and server if defined.
	if acc.remoteClientCert != "" && acc.remoteClientKey != "" {
		natsCtx.TLSCert = acc.remoteClientCert
		natsCtx.TLSKey = acc.remoteClientKey
	}
	if acc.remoteRootCA != "" {
		natsCtx.TLSCAs = []string{acc.remoteRootCA}
	}
	if acc.userCreds != "" {
		natsCtx.Credentials = acc.userCreds
	} else if acc.nkey != "" {
		natsCtx.Nkey = acc.nkey
	}

	if acc.user != "" && acc.password != "" {
		natsCtx.Username = acc.user
		natsCtx.Password = acc.password
	} else if acc.token != "" {
		natsCtx.Token = acc.token
	}

	if spec.tls != nil && len(spec.tls.RootCAs) > 0 {
		natsCtx.TLSCAs = spec.tls.RootCAs
	}

	natsServers := strings.Join(append(spec.servers, acc.servers...), ",")
	natsCtx.URL = natsServers
	c.normalEvent(o, "Connecting", "Connecting to new nats-servers")
	jsmc, err := jsm(natsCtx)
	if err != nil {
		return fmt.Errorf("failed to connect to nats-servers(%s): %w", natsServers, err)
	}

	defer jsmc.Close()

	return op(jsmc)
}

func splitNamespaceName(item interface{}) (ns string, name string, err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("failed to split namespace-name: %w", err)
		}
	}()

	key, ok := item.(string)
	if !ok {
		return "", "", fmt.Errorf("unexpected type: got=%T, want=%T", item, key)
	}

	ns, name, err = cache.SplitMetaNamespaceKey(key)
	if err != nil {
		return "", "", err
	}

	return ns, name, nil
}

func getStorageType(s string) (jsmapi.StorageType, error) {
	switch s {
	case strings.ToLower(jsmapi.FileStorage.String()):
		return jsmapi.FileStorage, nil
	case strings.ToLower(jsmapi.MemoryStorage.String()):
		return jsmapi.MemoryStorage, nil
	default:
		return 0, fmt.Errorf("invalid jetstream storage option: %s", s)
	}
}

func enqueueWork(q workqueue.TypedRateLimitingInterface[any], item interface{}) (err error) {
	key, err := cache.MetaNamespaceKeyFunc(item)
	if err != nil {
		return fmt.Errorf("failed to enqueue work: %w", err)
	}

	q.Add(key)
	return nil
}

type (
	jsmClientFunc func(*natsContext) (jsmClient, error)
	processorFunc func(ns, name string, jmsClient jsmClientFunc) error
)

func processQueueNext(q workqueue.TypedRateLimitingInterface[any], jmsClient jsmClientFunc, process processorFunc) {
	item, shutdown := q.Get()
	if shutdown {
		return
	}
	defer q.Done(item)

	ns, name, err := splitNamespaceName(item)
	if err != nil {
		// Probably junk, clean it up.
		utilruntime.HandleError(err)
		q.Forget(item)
		return
	}

	err = process(ns, name, jmsClient)
	if err == nil {
		// Item processed successfully, don't requeue.
		q.Forget(item)
		return
	}

	utilruntime.HandleError(err)

	if q.NumRequeues(item) < maxQueueRetries {
		// Failed to process item, try again.
		q.AddRateLimited(item)
		return
	}

	// If we haven't been able to recover by this point, then just stop.
	// The user should have enough info in kubectl describe to debug.
	q.Forget(item)
}

func UpsertCondition(cs []apis.Condition, next apis.Condition) []apis.Condition {
	for i := 0; i < len(cs); i++ {
		if cs[i].Type != next.Type {
			continue
		}

		cs[i] = next
		return cs
	}

	return append(cs, next)
}

func shouldEnqueue(prevObj, nextObj interface{}) bool {
	type crd interface {
		GetDeletionTimestamp() *k8smeta.Time
		GetSpec() interface{}
	}

	prev, ok := prevObj.(crd)
	if !ok {
		return false
	}

	next, ok := nextObj.(crd)
	if !ok {
		return false
	}

	markedDelete := next.GetDeletionTimestamp() != nil
	specChanged := !equality.Semantic.DeepEqual(prev.GetSpec(), next.GetSpec())

	return markedDelete || specChanged
}

func eventHandlers(q workqueue.TypedRateLimitingInterface[any]) cache.ResourceEventHandlerFuncs {
	return cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			if err := enqueueWork(q, obj); err != nil {
				utilruntime.HandleError(err)
			}
		},
		UpdateFunc: func(prev, next interface{}) {
			if !shouldEnqueue(prev, next) {
				return
			}

			if err := enqueueWork(q, next); err != nil {
				utilruntime.HandleError(err)
			}
		},
		DeleteFunc: func(obj interface{}) {
			if err := enqueueWork(q, obj); err != nil {
				utilruntime.HandleError(err)
			}
		},
	}
}


================================================
FILE: controllers/jetstream/controller_test.go
================================================
package jetstream

import (
	"context"
	"fmt"
	"os"
	"testing"
	"time"

	jsmapi "github.com/nats-io/jsm.go/api"
	apis "github.com/nats-io/nack/pkg/jetstream/apis/jetstream/v1beta2"

	k8sapis "k8s.io/api/core/v1"
	k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/client-go/util/workqueue"
)

func TestMain(m *testing.M) {
	// Disable error logs.
	utilruntime.ErrorHandlers = []utilruntime.ErrorHandler{
		func(ctx context.Context, err error, msg string, args ...any) {},
	}

	os.Exit(m.Run())
}

func TestGetStorageType(t *testing.T) {
	t.Parallel()

	cases := []struct {
		storage string

		wantType jsmapi.StorageType
		wantErr  bool
	}{
		{storage: "memory", wantType: jsmapi.MemoryStorage},
		{storage: "file", wantType: jsmapi.FileStorage},
		{storage: "junk", wantErr: true},
	}
	for _, c := range cases {
		c := c
		t.Run(c.storage, func(t *testing.T) {
			t.Parallel()

			got, err := getStorageType(c.storage)
			if err != nil && !c.wantErr {
				t.Error("unexpected error")
				t.Fatalf("got=%s; want=nil", err)
			} else if err == nil && c.wantErr {
				t.Error("unexpected success")
				t.Fatalf("got=nil; want=err")
			}

			if got != c.wantType {
				t.Error("unexpected storage type")
				t.Fatalf("got=%v; want=%v", got, c.wantType)
			}
		})
	}
}

func TestEnqueueWork(t *testing.T) {
	t.Parallel()

	limiter := workqueue.DefaultTypedControllerRateLimiter[any]()
	q := workqueue.NewNamedRateLimitingQueue(limiter, "StreamsTest")
	defer q.ShutDown()

	s := &apis.Stream{
		ObjectMeta: k8smeta.ObjectMeta{
			Namespace: "default",
			Name:      "my-stream",
		},
	}

	if err := enqueueWork(q, s); err != nil {
		t.Fatal(err)
	}

	if got, want := q.Len(), 1; got != want {
		t.Error("unexpected queue length")
		t.Fatalf("got=%d; want=%d", got, want)
	}

	wantItem := fmt.Sprintf("%s/%s", s.Namespace, s.Name)
	gotItem, _ := q.Get()
	if gotItem != wantItem {
		t.Error("unexpected queue item")
		t.Fatalf("got=%s; want=%s", gotItem, wantItem)
	}
}

func TestProcessQueueNext(t *testing.T) {
	t.Parallel()

	t.Run("bad item key", func(t *testing.T) {
		t.Parallel()

		limiter := workqueue.DefaultTypedControllerRateLimiter[any]()
		q := workqueue.NewNamedRateLimitingQueue(limiter, "StreamsTest")
		defer q.ShutDown()

		key := "this/is/a/bad/key"
		q.Add(key)

		processQueueNext(q, testWrapJSMC(&mockJsmClient{}), func(ns, name string, c jsmClientFunc) error {
			return nil
		})

		if got, want := q.Len(), 0; got != want {
			t.Error("unexpected number of items in queue")
			t.Fatalf("got=%d; want=%d", got, want)
		}

		if got, want := q.NumRequeues(key), 0; got != want {
			t.Error("unexpected number of requeues")
			t.Fatalf("got=%d; want=%d", got, want)
		}
	})

	t.Run("process error", func(t *testing.T) {
		t.Parallel()

		limiter := workqueue.DefaultTypedControllerRateLimiter[any]()
		q := workqueue.NewNamedRateLimitingQueue(limiter, "StreamsTest")
		defer q.ShutDown()

		ns, name := "default", "mystream"
		key := fmt.Sprintf("%s/%s", ns, name)
		q.Add(key)

		maxGets := maxQueueRetries + 1
		numRequeues := -1
		for i := 0; i < maxGets; i++ {
			if i == maxGets-1 {
				numRequeues = q.NumRequeues(key)
			}

			processQueueNext(q, testWrapJSMC(&mockJsmClient{}), func(ns, name string, c jsmClientFunc) error {
				return fmt.Errorf("processing error")
			})
		}

		if got, want := q.Len(), 0; got != want {
			t.Error("unexpected number of items in queue")
			t.Fatalf("got=%d; want=%d", got, want)
		}

		if got, want := numRequeues, 10; got != want {
			t.Error("unexpected number of requeues")
			t.Fatalf("got=%d; want=%d", got, want)
		}
	})

	t.Run("process ok", func(t *testing.T) {
		t.Parallel()

		limiter := workqueue.DefaultTypedControllerRateLimiter[any]()
		q := workqueue.NewNamedRateLimitingQueue(limiter, "StreamsTest")
		defer q.ShutDown()

		ns, name := "default", "mystream"
		key := fmt.Sprintf("%s/%s", ns, name)
		q.Add(key)

		numRequeues := q.NumRequeues(key)
		processQueueNext(q, testWrapJSMC(&mockJsmClient{}), func(ns, name string, c jsmClientFunc) error {
			return nil
		})

		if got, want := q.Len(), 0; got != want {
			t.Error("unexpected number of items in queue")
			t.Fatalf("got=%d; want=%d", got, want)
		}

		if got, want := numRequeues, 0; got != want {
			t.Error("unexpected number of requeues")
			t.Fatalf("got=%d; want=%d", got, want)
		}
	})
}

func TestUpsertCondition(t *testing.T) {
	t.Parallel()

	var cs []apis.Condition

	cs = UpsertCondition(cs, apis.Condition{
		Type:               readyCondType,
		Status:             k8sapis.ConditionTrue,
		LastTransitionTime: time.Now().UTC().Format(time.RFC3339Nano),
		Reason:             "Synced",
		Message:            "Stream is synced with spec",
	})
	if got, want := len(cs), 1; got != want {
		t.Error("unexpected len conditions")
		t.Fatalf("got=%d; want=%d", got, want)
	}
	if got, want := cs[0].Reason, "Synced"; got != want {
		t.Error("unexpected reason")
		t.Fatalf("got=%s; want=%s", got, want)
	}

	cs = UpsertCondition(cs, apis.Condition{
		Type:               readyCondType,
		Status:             k8sapis.ConditionFalse,
		LastTransitionTime: time.Now().UTC().Format(time.RFC3339Nano),
		Reason:             "Errored",
		Message:            "invalid foo",
	})
	if got, want := len(cs), 1; got != want {
		t.Error("unexpected len conditions")
		t.Fatalf("got=%d; want=%d", got, want)
	}
	if got, want := cs[0].Reason, "Errored"; got != want {
		t.Error("unexpected reason")
		t.Fatalf("got=%s; want=%s", got, want)
	}

	cs = UpsertCondition(cs, apis.Condition{
		Type:               "Foo",
		Status:             k8sapis.ConditionTrue,
		LastTransitionTime: time.Now().UTC().Format(time.RFC3339Nano),
		Reason:             "Bar",
		Message:            "bar ok",
	})
	if got, want := len(cs), 2; got != want {
		t.Error("unexpected len conditions")
		t.Fatalf("got=%d; want=%d", got, want)
	}
	if got, want := cs[1].Reason, "Bar"; got != want {
		t.Error("unexpected reason")
		t.Fatalf("got=%s; want=%s", got, want)
	}
}

func TestShouldEnqueue(t *testing.T) {
	t.Parallel()

	ts := k8smeta.NewTime(time.Now())

	cases := []struct {
		name string
		prev interface{}
		next interface{}

		want bool
	}{
		{
			name: "stream deleted",
			prev: &apis.Stream{
				ObjectMeta: k8smeta.ObjectMeta{
					Namespace: "default",
					Name:      "obj-name",
				},
			},
			next: &apis.Stream{
				ObjectMeta: k8smeta.ObjectMeta{
					Namespace:         "default",
					Name:              "obj-name",
					DeletionTimestamp: &ts,
				},
			},
			want: true,
		},
		{
			name: "stream spec changed",
			prev: &apis.Stream{
				ObjectMeta: k8smeta.ObjectMeta{
					Namespace: "default",
					Name:      "obj-name",
				},
				Spec: apis.StreamSpec{
					Name: "foo",
				},
			},
			next: &apis.Stream{
				ObjectMeta: k8smeta.ObjectMeta{
					Namespace: "default",
					Name:      "obj-name",
				},
				Spec: apis.StreamSpec{
					Name: "bar",
				},
			},
			want: true,
		},
		{
			name: "consumer deleted",
			prev: &apis.Consumer{
				ObjectMeta: k8smeta.ObjectMeta{
					Namespace: "default",
					Name:      "obj-name",
				},
			},
			next: &apis.Consumer{
				ObjectMeta: k8smeta.ObjectMeta{
					Namespace:         "default",
					Name:              "obj-name",
					DeletionTimestamp: &ts,
				},
			},
			want: true,
		},
		{
			name: "consumer spec changed",
			prev: &apis.Consumer{
				ObjectMeta: k8smeta.ObjectMeta{
					Namespace: "default",
					Name:      "obj-name",
				},
				Spec: apis.ConsumerSpec{
					DurableName: "foo",
				},
			},
			next: &apis.Consumer{
				ObjectMeta: k8smeta.ObjectMeta{
					Namespace: "default",
					Name:      "obj-name",
				},
				Spec: apis.ConsumerSpec{
					DurableName: "bar",
				},
			},
			want: true,
		},
	}

	for _, c := range cases {
		c := c
		t.Run(c.name, func(t *testing.T) {
			t.Parallel()

			got := shouldEnqueue(c.prev, c.next)
			if got != c.want {
				t.Fatalf("got=%t; want=%t", got, c.want)
			}
		})
	}
}


================================================
FILE: controllers/jetstream/jsmclient.go
================================================
package jetstream

import (
	"context"

	"github.com/nats-io/jsm.go"
	jsmapi "github.com/nats-io/jsm.go/api"
	"github.com/nats-io/nats.go"
	"github.com/sirupsen/logrus"
)

type jsmClient interface {
	Connect(servers string, opts ...nats.Option) error
	Close()

	LoadStream(ctx context.Context, name string) (jsmStream, error)
	NewStream(ctx context.Context, name string, opts []jsm.StreamOption) (jsmStream, error)

	LoadConsumer(ctx context.Context, stream, consumer string) (jsmConsumer, error)
	NewConsumer(ctx context.Context, stream string, opts []jsm.ConsumerOption) (jsmConsumer, error)
}

type jsmStream interface {
	UpdateConfiguration(cnf jsmapi.StreamConfig, opts ...jsm.StreamOption) error
	Delete() error
}

type jsmConsumer interface {
	UpdateConfiguration(opts ...jsm.ConsumerOption) error
	Delete() error
}

type realJsmClient struct {
	pooledNc *pooledNatsConn
	jm       *jsm.Manager
}

func (c *realJsmClient) Connect(servers string, opts ...nats.Option) error {
	connPool := newNatsConnPool(logrus.New(), &natsContextDefaults{URL: servers}, opts)
	pooledNc, err := connPool.Get(&natsContext{})
	if err != nil {
		return err
	}
	c.pooledNc = pooledNc

	m, err := jsm.New(pooledNc.nc)
	if err != nil {
		return err
	}
	c.jm = m

	return nil
}

func (c *realJsmClient) Close() {
	c.pooledNc.ReturnToPool()
}

func (c *realJsmClient) LoadStream(_ context.Context, name string) (jsmStream, error) {
	return c.jm.LoadStream(name)
}

func (c *realJsmClient) NewStream(_ context.Context, name string, opts []jsm.StreamOption) (jsmStream, error) {
	return c.jm.NewStream(name, opts...)
}

func (c *realJsmClient) LoadConsumer(_ context.Context, stream, consumer string) (jsmConsumer, error) {
	return c.jm.LoadConsumer(stream, consumer)
}

func (c *realJsmClient) NewConsumer(_ context.Context, stream string, opts []jsm.ConsumerOption) (jsmConsumer, error) {
	return c.jm.NewConsumer(stream, opts...)
}


================================================
FILE: controllers/jetstream/jsmclient_test.go
================================================
package jetstream

import (
	"context"

	"github.com/nats-io/jsm.go"
	jsmapi "github.com/nats-io/jsm.go/api"
	"github.com/nats-io/nats.go"
)

type mockStream struct {
	deleteErr            error
	capturedConfig       *jsmapi.StreamConfig
	updateConfigCallback func(cnf jsmapi.StreamConfig) error
}

func (m *mockStream) UpdateConfiguration(cnf jsmapi.StreamConfig, opts ...jsm.StreamOption) error {
	if m.capturedConfig != nil {
		*m.capturedConfig = cnf
	}
	if m.updateConfigCallback != nil {
		return m.updateConfigCallback(cnf)
	}
	return nil
}

func (m *mockStream) Delete() error {
	return m.deleteErr
}

type mockConsumer struct {
	deleteErr error
}

func (m *mockConsumer) UpdateConfiguration(opts ...jsm.ConsumerOption) error {
	return nil
}

func (m *mockConsumer) Delete() error {
	return m.deleteErr
}

type mockJsmClient struct {
	connectErr error

	loadStream    jsmStream
	loadStreamErr error
	newStream     jsmStream
	newStreamErr  error

	loadConsumer    jsmConsumer
	loadConsumerErr error
	newConsumer     jsmConsumer
	newConsumerErr  error
}

func (c *mockJsmClient) Connect(servers string, opts ...nats.Option) error {
	return c.connectErr
}

func (c *mockJsmClient) Close() {}

func (c *mockJsmClient) LoadStream(ctx context.Context, name string) (jsmStream, error) {
	return c.loadStream, c.loadStreamErr
}

func (c *mockJsmClient) NewStream(ctx context.Context, name string, opt []jsm.StreamOption) (jsmStream, error) {
	return c.newStream, c.newStreamErr
}

func (c *mockJsmClient) LoadConsumer(ctx context.Context, stream, consumer string) (jsmConsumer, error) {
	return c.loadConsumer, c.loadConsumerErr
}

func (c *mockJsmClient) NewConsumer(ctx context.Context, stream string, opts []jsm.ConsumerOption) (jsmConsumer, error) {
	return c.newConsumer, c.newConsumerErr
}


================================================
FILE: controllers/jetstream/stream.go
================================================
// Copyright 2020 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package jetstream

import (
	"context"
	"errors"
	"fmt"
	"time"

	jsm "github.com/nats-io/jsm.go"
	jsmapi "github.com/nats-io/jsm.go/api"
	apis "github.com/nats-io/nack/pkg/jetstream/apis/jetstream/v1beta2"
	typed "github.com/nats-io/nack/pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2"
	k8sapi "k8s.io/api/core/v1"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/util/retry"
	klog "k8s.io/klog/v2"
)

func (c *Controller) runStreamQueue() {
	for {
		processQueueNext(c.strQueue, c.RealJSMC, c.processStream)
	}
}

func (c *Controller) processStream(ns, name string, jsm jsmClientFunc) (err error) {
	str, err := c.strLister.Streams(ns).Get(name)
	if err != nil && k8serrors.IsNotFound(err) {
		return nil
	} else if err != nil {
		return err
	}

	return c.processStreamObject(str, jsm)
}

func (c *Controller) processStreamObject(str *apis.Stream, jsm jsmClientFunc) (err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("failed to process stream: %w", err)
		}
	}()

	spec := str.Spec
	ifc := c.ji.Streams(str.Namespace)
	ns := str.Namespace
	readOnly := c.opts.ReadOnly

	acc, err := c.getAccountOverrides(spec.Account, ns)
	if err != nil {
		return err
	}

	defer func() {
		if err == nil {
			return
		}

		if _, serr := setStreamErrored(c.ctx, str, ifc, err); serr != nil {
			err = fmt.Errorf("%s: %w", err, serr)
		}
	}()

	type operator func(ctx context.Context, c jsmClient, spec apis.StreamSpec) (err error)

	natsClientUtil := func(op operator) error {
		return c.runWithJsmc(jsm, acc, &jsmcSpecOverrides{
			servers: spec.Servers,
			tls:     spec.TLS,
			creds:   spec.Creds,
			nkey:    spec.Nkey,
		}, str, func(jsmc jsmClient) error {
			return op(c.ctx, jsmc, spec)
		})
	}

	deleteOK := str.GetDeletionTimestamp() != nil
	newGeneration := str.Generation != str.Status.ObservedGeneration
	strOK := true
	err = natsClientUtil(streamExists)
	var apierr jsmapi.ApiError
	if errors.As(err, &apierr) && apierr.NotFoundError() {
		strOK = false
	} else if err != nil {
		return err
	}
	updateOK := (strOK && !deleteOK && newGeneration)
	createOK := (!strOK && !deleteOK) || (!updateOK && !deleteOK && newGeneration)

	switch {
	case createOK:
		if readOnly {
			c.normalEvent(str, "SkipCreate", fmt.Sprintf("Skip creating stream %q", spec.Name))
			return nil
		}
		c.normalEvent(str, "Creating", fmt.Sprintf("Creating stream %q", spec.Name))
		if err := natsClientUtil(createStream); err != nil {
			return err
		}

		if _, err := setStreamOK(c.ctx, str, ifc); err != nil {
			return err
		}
		c.normalEvent(str, "Created", fmt.Sprintf("Created stream %q", spec.Name))
	case updateOK:
		if str.Spec.PreventUpdate || readOnly {
			c.normalEvent(str, "SkipUpdate", fmt.Sprintf("Skip updating stream %q", spec.Name))
			if _, err := setStreamOK(c.ctx, str, ifc); err != nil {
				return err
			}
			return nil
		}
		c.normalEvent(str, "Updating", fmt.Sprintf("Updating stream %q", spec.Name))
		if err := natsClientUtil(updateStream); err != nil {
			return err
		}

		if _, err := setStreamOK(c.ctx, str, ifc); err != nil {
			return err
		}
		c.normalEvent(str, "Updated", fmt.Sprintf("Updated stream %q", spec.Name))
		return nil
	case deleteOK:
		if str.Spec.PreventDelete || readOnly {
			c.normalEvent(str, "SkipDelete", fmt.Sprintf("Skip deleting stream %q", spec.Name))
			if _, err := setStreamOK(c.ctx, str, ifc); err != nil {
				return err
			}
			return nil
		}
		c.normalEvent(str, "Deleting", fmt.Sprintf("Deleting stream %q", spec.Name))
		if err := natsClientUtil(deleteStream); err != nil {
			return err
		}
	default:
		c.normalEvent(str, "Noop", fmt.Sprintf("Nothing done for stream %q (prevent-delete=%v, prevent-update=%v)",
			spec.Name, spec.PreventDelete, spec.PreventUpdate,
		))
		// Noop events only update the status of the CRD.
		if _, err := setStreamOK(c.ctx, str, ifc); err != nil {
			return err
		}
	}

	return nil
}

func streamExists(ctx context.Context, c jsmClient, spec apis.StreamSpec) (err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("failed to check if stream exists: %w", err)
		}
	}()

	_, err = c.LoadStream(ctx, spec.Name)
	return err
}

func createStream(ctx context.Context, c jsmClient, spec apis.StreamSpec) (err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("failed to create stream %q: %w", spec.Name, err)
		}
	}()

	maxAge, err := getDurationFromString(spec.MaxAge)
	if err != nil {
		return err
	}

	duplicates, err := getDuplicates(spec.DuplicateWindow)
	if err != nil {
		return err
	}

	opts := []jsm.StreamOption{
		jsm.Subjects(spec.Subjects...),
		jsm.MaxConsumers(spec.MaxConsumers),
		jsm.MaxMessageSize(int32(spec.MaxMsgSize)),
		jsm.MaxMessages(int64(spec.MaxMsgs)),
		jsm.Replicas(spec.Replicas),
		jsm.DuplicateWindow(duplicates),
		jsm.MaxAge(maxAge),
		jsm.MaxBytes(int64(spec.MaxBytes)),
	}

	switch spec.Retention {
	case "limits":
		opts = append(opts, jsm.LimitsRetention())
	case "interest":
		opts = append(opts, jsm.InterestRetention())
	case "workqueue":
		opts = append(opts, jsm.WorkQueueRetention())
	}

	switch spec.Storage {
	case "file":
		opts = append(opts, jsm.FileStorage())
	case "memory":
		opts = append(opts, jsm.MemoryStorage())
	}

	switch spec.Discard {
	case "old":
		opts = append(opts, jsm.DiscardOld())
	case "new":
		opts = append(opts, jsm.DiscardNew())
	}

	switch spec.Compression {
	case "s2":
		opts = append(opts, jsm.Compression(jsmapi.S2Compression))
	case "none":
		opts = append(opts, jsm.Compression(jsmapi.NoCompression))
	}

	if spec.NoAck {
		opts = append(opts, jsm.NoAck())
	}

	if spec.Description != "" {
		opts = append(opts, func(o *jsmapi.StreamConfig) error {
			o.Description = spec.Description
			return nil
		})
	}

	if spec.MaxMsgsPerSubject > 0 {
		opts = append(opts, func(o *jsmapi.StreamConfig) error {
			o.MaxMsgsPer = int64(spec.MaxMsgsPerSubject)
			return nil
		})
	}

	if spec.Mirror != nil {
		ss, err := getStreamSource(spec.Mirror)
		if err != nil {
			return err
		}

		opts = append(opts, func(o *jsmapi.StreamConfig) error {
			o.Mirror = ss
			return nil
		})
	}

	if spec.Placement != nil {
		opts = append(opts, func(o *jsmapi.StreamConfig) error {
			o.Placement = &jsmapi.Placement{
				Cluster: spec.Placement.Cluster,
				Tags:    spec.Placement.Tags,
			}
			return nil
		})
	}

	var srcs []*jsmapi.StreamSource
	for _, ss := range spec.Sources {
		jss, err := getStreamSource(ss)
		if err != nil {
			return err
		}
		srcs = append(srcs, jss)
	}
	opts = append(opts, func(o *jsmapi.StreamConfig) error {
		o.Sources = srcs
		return nil
	})

	if spec.RePublish != nil {
		opts = append(opts, jsm.Republish(&jsmapi.RePublish{
			Source:      spec.RePublish.Source,
			Destination: spec.RePublish.Destination,
		}))
	}

	if spec.SubjectTransform != nil {
		opts = append(opts, func(o *jsmapi.StreamConfig) error {
			o.SubjectTransform = &jsmapi.SubjectTransformConfig{
				Source:      spec.SubjectTransform.Source,
				Destination: spec.SubjectTransform.Dest,
			}
			return nil
		})
	}

	if spec.AllowDirect {
		opts = append(opts, jsm.AllowDirect())
	}

	if spec.AllowRollup {
		opts = append(opts, jsm.AllowRollup())
	}

	if spec.DenyDelete {
		opts = append(opts, jsm.DenyDelete())
	}

	if spec.DenyPurge {
		opts = append(opts, jsm.DenyPurge())
	}

	if spec.DiscardPerSubject {
		opts = append(opts, jsm.DiscardNewPerSubject())
	}

	if spec.FirstSequence != 0 {
		opts = append(opts, jsm.FirstSequence(spec.FirstSequence))
	}

	if spec.Metadata != nil {
		opts = append(opts, jsm.StreamMetadata(spec.Metadata))
	}

	if spec.AllowMsgTTL {
		opts = append(opts, jsm.AllowMsgTTL())
	}

	if spec.SubjectDeleteMarkerTTL != "" {
		d, err := time.ParseDuration(spec.SubjectDeleteMarkerTTL)
		if err != nil {
			return fmt.Errorf("parse subject delete marker TTL: %w", err)
		}
		opts = append(opts, jsm.SubjectDeleteMarkerTTL(d))
	}

	if spec.AllowMsgCounter {
		opts = append(opts, func(o *jsmapi.StreamConfig) error {
			o.AllowMsgCounter = true
			return nil
		})
	}

	if spec.AllowAtomicPublish {
		opts = append(opts, func(o *jsmapi.StreamConfig) error {
			o.AllowAtomicPublish = true
			return nil
		})
	}

	if spec.AllowMsgSchedules {
		opts = append(opts, func(o *jsmapi.StreamConfig) error {
			o.AllowMsgSchedules = true
			return nil
		})
	}

	if spec.PersistMode == "async" {
		opts = append(opts, func(o *jsmapi.StreamConfig) error {
			o.PersistMode = jsmapi.AsyncPersistMode
			return nil
		})
	} else if spec.PersistMode == "default" {
		opts = append(opts, func(o *jsmapi.StreamConfig) error {
			o.PersistMode = jsmapi.DefaultPersistMode
			return nil
		})
	}

	_, err = c.NewStream(ctx, spec.Name, opts)
	return err
}

func updateStream(ctx context.Context, c jsmClient, spec apis.StreamSpec) (err error) {
	defer func() {
		if err != nil {
			err = fmt.Errorf("failed to update stream %q: %w", spec.Name, err)
		}
	}()

	js, err := c.LoadStream(ctx, spec.Name)
	if err != nil {
		return err
	}

	maxAge, err := getDurationFromString(spec.MaxAge)
	if err != nil {
		return err
	}

	subjectDeleteMarkerTTL, err := getDurationFromString(spec.SubjectDeleteMarkerTTL)
	if err != nil {
		return err
	}

	retention := getRetention(spec.Retention)
	storage := getStorage(spec.Storage)
	discard := getDiscard(spec.Discard)

	duplicates, err := getDuplicates(spec.DuplicateWindow)
	if err != nil {
		return err
	}

	var subjectTransform *jsmapi.SubjectTransformConfig
	if spec.SubjectTransform != nil {
		subjectTransform = &jsmapi.SubjectTransformConfig{
			Source:      spec.SubjectTransform.Source,
			Destination: spec.SubjectTransform.Dest,
		}
	}

	config := jsmapi.StreamConfig{
		Name:                   spec.Name,
		Description:            spec.Description,
		Retention:              retention,
		Subjects:               spec.Subjects,
		MaxConsumers:           spec.MaxConsumers,
		MaxMsgs:                int64(spec.MaxMsgs),
		MaxBytes:               int64(spec.MaxBytes),
		MaxMsgsPer:             int64(spec.MaxMsgsPerSubject),
		MaxAge:                 maxAge,
		MaxMsgSize:             int32(spec.MaxMsgSize),
		Storage:                storage,
		Discard:                discard,
		DiscardNewPer:          spec.DiscardPerSubject,
		Replicas:               spec.Replicas,
		NoAck:                  spec.NoAck,
		Duplicates:             duplicates,
		AllowDirect:            spec.AllowDirect,
		DenyDelete:             spec.DenyDelete,
		DenyPurge:              spec.DenyPurge,
		RollupAllowed:          spec.AllowRollup,
		FirstSeq:               spec.FirstSequence,
		SubjectTransform:       subjectTransform,
		AllowMsgTTL:            spec.AllowMsgTTL,
		SubjectDeleteMarkerTTL: subjectDeleteMarkerTTL,
		AllowMsgCounter:        spec.AllowMsgCounter,
		AllowAtomicPublish:     spec.AllowAtomicPublish,
		AllowMsgSchedules:      spec.AllowMsgSchedules,
	}
	if spec.RePublish != nil {
		config.RePublish = &jsmapi.RePublish{
			Source:      spec.RePublish.Source,
			Destination: spec.RePublish.Destination,
			HeadersOnly: spec.RePublish.HeadersOnly,
		}
	}
	if spec.Mirror != nil {
		ss, err := getStreamSource(spec.Mirror)
		if err != nil {
			return err
		}

		config.Mirror = ss
	}
	config.Sources = make([]*jsmapi.StreamSource, len(spec.Sources))
	for i, ss := range spec.Sources {
		jss, err := getStreamSource(ss)
		if err != nil {
			return err
		}
		config.Sources[i] = jss
	}

	if spec.Placement != nil {
		config.Placement = &jsmapi.Placement{
			Cluster: spec.Placement.Cluster,
			Tags:    spec.Placement.Tags,
		}
	}

	if spec.Metadata != nil {
		config.Metadata = spec.Metadata
	}

	switch spec.Compression {
	case "s2":
		config.Compression = jsmapi.S2Compression
	case "none":
		config.Compression = jsmapi.NoCompression
	}

	// Handle PersistMode
	if spec.PersistMode == "async" {
		config.PersistMode = jsmapi.AsyncPersistMode
	} else if spec.PersistMode == "default" {
		config.PersistMode = jsmapi.DefaultPersistMode
	}

	return js.UpdateConfiguration(config)
}

func deleteStream(ctx context.Context, c jsmClient, spec apis.StreamSpec) (err error) {
	name := spec.Name
	defer func() {
		if err != nil {
			err = fmt.Errorf("failed to delete stream %q: %w", name, err)
		}
	}()

	if spec.PreventDelete {
		klog.Infof("Stream %q is configured to preventDelete:\n", name)
		return nil
	}

	var apierr jsmapi.ApiError
	str, err := c.LoadStream(ctx, name)
	if errors.As(err, &apierr) && apierr.NotFoundError() {
		return nil
	} else if err != nil {
		return err
	}

	return str.Delete()
}

func setStreamErrored(ctx context.Context, s *apis.Stream, sif typed.StreamInterface, err error) (*apis.Stream, error) {
	if err == nil {
		return s, nil
	}

	sc := s.DeepCopy()
	sc.Status.Conditions = UpsertCondition(sc.Status.Conditions, apis.Condition{
		Type:               readyCondType,
		Status:             k8sapi.ConditionFalse,
		LastTransitionTime: time.Now().UTC().Format(time.RFC3339Nano),
		Reason:             "Errored",
		Message:            err.Error(),
	})

	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	var res *apis.Stream
	err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
		var err error
		ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
		defer cancel()
		res, err = sif.UpdateStatus(ctx, sc, k8smeta.UpdateOptions{})
		if err != nil {
			return fmt.Errorf("failed to set stream errored status: %w", err)
		}
		return nil
	})
	return res, err
}

func setStreamOK(ctx context.Context, s *apis.Stream, i typed.StreamInterface) (*apis.Stream, error) {
	sc := s.DeepCopy()

	sc.Status.ObservedGeneration = s.Generation
	sc.Status.Conditions = UpsertCondition(sc.Status.Conditions, apis.Condition{
		Type:               readyCondType,
		Status:             k8sapi.ConditionTrue,
		LastTransitionTime: time.Now().UTC().Format(time.RFC3339Nano),
		Reason:             "Created",
		Message:            "Stream successfully created",
	})

	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	var res *apis.Stream
	err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
		var err error
		ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
		defer cancel()
		res, err = i.UpdateStatus(ctx, sc, k8smeta.UpdateOptions{})
		if err != nil {
			return fmt.Errorf("failed to set stream %q status: %w", s.Spec.Name, err)
		}
		return nil
	})
	return res, err
}

func getDurationFromString(v string) (time.Duration, error) {
	if v == "" {
		return time.Duration(0), nil
	}

	return time.ParseDuration(v)
}

func getRetention(v string) jsmapi.RetentionPolicy {
	retention := jsmapi.LimitsPolicy
	switch v {
	case "interest":
		retention = jsmapi.InterestPolicy
	case "workqueue":
		retention = jsmapi.WorkQueuePolicy
	}
	return retention
}

func getStorage(v string) jsmapi.StorageType {
	storage := jsmapi.MemoryStorage
	switch v {
	case "file":
		storage = jsmapi.FileStorage
	}
	return storage
}

func getDiscard(v string) jsmapi.DiscardPolicy {
	discard := jsmapi.DiscardOld
	switch v {
	case "new":
		discard = jsmapi.DiscardNew
	}
	return discard
}

func getDuplicates(v string) (time.Duration, error) {
	if v == "" {
		return time.Duration(0), nil
	}

	return time.ParseDuration(v)
}

func getStreamSource(ss *apis.StreamSource) (*jsmapi.StreamSource, error) {
	jss := &jsmapi.StreamSource{
		Name:          ss.Name,
		FilterSubject: ss.FilterSubject,
	}

	if ss.OptStartSeq > 0 {
		jss.OptStartSeq = uint64(ss.OptStartSeq)
	} else if ss.OptStartTime != "" {
		t, err := time.Parse(time.RFC3339, ss.OptStartTime)
		if err != nil {
			return nil, err
		}
		jss.OptStartTime = &t
	}

	if ss.ExternalAPIPrefix != "" || ss.ExternalDeliverPrefix != "" {
		jss.External = &jsmapi.ExternalStream{
			ApiPrefix:     ss.ExternalAPIPrefix,
			DeliverPrefix: ss.ExternalDeliverPrefix,
		}
	}

	for _, transform := range ss.SubjectTransforms {
		jss.SubjectTransforms = append(jss.SubjectTransforms, jsmapi.SubjectTransformConfig{
			Source:      transform.Source,
			Destination: transform.Dest,
		})
	}

	return jss, nil
}


================================================
FILE: controllers/jetstream/stream_test.go
================================================
package jetstream

import (
	"context"
	"errors"
	"strings"
	"testing"

	jsmapi "github.com/nats-io/jsm.go/api"

	apis "github.com/nats-io/nack/pkg/jetstream/apis/jetstream/v1beta2"
	clientsetfake "github.com/nats-io/nack/pkg/jetstream/generated/clientset/versioned/fake"

	k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	k8sclientsetfake "k8s.io/client-go/kubernetes/fake"
	k8stesting "k8s.io/client-go/testing"
	"k8s.io/client-go/tools/record"
)

func TestProcessStream(t *testing.T) {
	t.Parallel()

	updateObject := func(a k8stesting.Action) (handled bool, o runtime.Object, err error) {
		ua, ok := a.(k8stesting.UpdateAction)
		if !ok {
			return false, nil, nil
		}

		return true, ua.GetObject(), nil
	}

	t.Run("create stream", func(t *testing.T) {
		t.Parallel()

		jc := clientsetfake.NewSimpleClientset()
		wantEvents := 2
		rec := record.NewFakeRecorder(wantEvents)
		ctrl := NewController(Options{
			Ctx:            context.Background(),
			KubeIface:      k8sclientsetfake.NewSimpleClientset(),
			JetstreamIface: jc,
			Recorder:       rec,
		})

		ns, name := "default", "my-stream"

		informer := ctrl.informerFactory.Jetstream().V1beta2().Streams()
		err := informer.Informer().GetStore().Add(&apis.Stream{
			ObjectMeta: k8smeta.ObjectMeta{
				Namespace:  ns,
				Name:       name,
				Generation: 1,
			},
			Spec: apis.StreamSpec{
				Name:    name,
				MaxAge:  "1h",
				Storage: "memory",
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		jc.PrependReactor("update", "streams", updateObject)

		notFoundErr := jsmapi.ApiError{Code: 404}
		jsmc := &mockJsmClient{
			loadStreamErr: notFoundErr,
		}
		if err := ctrl.processStream(ns, name, testWrapJSMC(jsmc)); err != nil {
			t.Fatal(err)
		}

		if got := len(rec.Events); got != wantEvents {
			t.Error("unexpected number of events")
			t.Fatalf("got=%d; want=%d", got, wantEvents)
		}

		<-rec.Events
		<-rec.Events
		for i := 0; i < len(rec.Events); i++ {
			gotEvent := <-rec.Events
			if !strings.Contains(gotEvent, "Creat") {
				t.Error("unexpected event")
				t.Fatalf("got=%s; want=%s", gotEvent, "Creating/Created...")
			}
		}
	})

	t.Run("update stream", func(t *testing.T) {
		t.Parallel()

		jc := clientsetfake.NewSimpleClientset()
		wantEvents := 2
		rec := record.NewFakeRecorder(wantEvents)
		ctrl := NewController(Options{
			Ctx:            context.Background(),
			KubeIface:      k8sclientsetfake.NewSimpleClientset(),
			JetstreamIface: jc,
			Recorder:       rec,
		})

		ns, name := "default", "my-stream"

		informer := ctrl.informerFactory.Jetstream().V1beta2().Streams()
		err := informer.Informer().GetStore().Add(&apis.Stream{
			ObjectMeta: k8smeta.ObjectMeta{
				Namespace:  ns,
				Name:       name,
				Generation: 2,
			},
			Spec: apis.StreamSpec{
				Name:              name,
				MaxAge:            "1h",
				Storage:           "memory",
				AllowMsgSchedules: true,
			},
			Status: apis.Status{
				ObservedGeneration: 1,
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		jc.PrependReactor("update", "streams", updateObject)

		// Capture the config that gets passed to UpdateConfiguration
		var capturedConfig jsmapi.StreamConfig
		jsmc := &mockJsmClient{
			loadStreamErr: nil,
			loadStream: &mockStream{
				capturedConfig: &capturedConfig,
			},
		}
		if err := ctrl.processStream(ns, name, testWrapJSMC(jsmc)); err != nil {
			t.Fatal(err)
		}

		// Verify that AllowMsgSchedules was set in the config
		if !capturedConfig.AllowMsgSchedules {
			t.Errorf("AllowMsgSchedules not set in stream config during update: got=%v, want=true", capturedConfig.AllowMsgSchedules)
		}

		if got := len(rec.Events); got != wantEvents {
			t.Error("unexpected number of events")
			t.Fatalf("got=%d; want=%d", got, wantEvents)
		}

		for i := 0; i < len(rec.Events); i++ {
			gotEvent := <-rec.Events
			if !strings.Contains(gotEvent, "Updat") {
				t.Error("unexpected event")
				t.Fatalf("got=%s; want=%s", gotEvent, "Updating/Updated...")
			}
		}
	})

	t.Run("delete stream", func(t *testing.T) {
		t.Parallel()

		jc := clientsetfake.NewSimpleClientset()
		wantEvents := 1
		rec := record.NewFakeRecorder(wantEvents)
		ctrl := NewController(Options{
			Ctx:            context.Background(),
			KubeIface:      k8sclientsetfake.NewSimpleClientset(),
			JetstreamIface: jc,
			Recorder:       rec,
		})

		ts := k8smeta.Unix(1600216923, 0)
		ns, name := "default", "my-stream"

		informer := ctrl.informerFactory.Jetstream().V1beta2().Streams()
		err := informer.Informer().GetStore().Add(&apis.Stream{
			ObjectMeta: k8smeta.ObjectMeta{
				Namespace:         ns,
				Name:              name,
				Generation:        2,
				DeletionTimestamp: &ts,
			},
			Spec: apis.StreamSpec{
				Name:    name,
				MaxAge:  "1h",
				Storage: "memory",
			},
			Status: apis.Status{
				ObservedGeneration: 1,
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		jc.PrependReactor("update", "streams", updateObject)

		jsmc := &mockJsmClient{
			loadStreamErr: nil,
			loadStream:    &mockStream{},
		}
		if err := ctrl.processStream(ns, name, testWrapJSMC(jsmc)); err != nil {
			t.Fatal(err)
		}

		if got := len(rec.Events); got != wantEvents {
			t.Error("unexpected number of events")
			t.Fatalf("got=%d; want=%d", got, wantEvents)
		}

		for i := 0; i < len(rec.Events); i++ {
			gotEvent := <-rec.Events
			if !strings.Contains(gotEvent, "Delet") {
				t.Error("unexpected event")
				t.Fatalf("got=%s; want=%s", gotEvent, "Deleting/Deleted...")
			}
		}
	})

	t.Run("process error", func(t *testing.T) {
		t.Parallel()

		jc := clientsetfake.NewSimpleClientset()
		wantEvents := 4
		rec := record.NewFakeRecorder(wantEvents)
		ctrl := NewController(Options{
			Ctx:            context.Background(),
			KubeIface:      k8sclientsetfake.NewSimpleClientset(),
			JetstreamIface: jc,
			Recorder:       rec,
		})

		ns, name := "default", "my-stream"

		informer := ctrl.informerFactory.Jetstream().V1beta2().Streams()
		err := informer.Informer().GetStore().Add(&apis.Stream{
			ObjectMeta: k8smeta.ObjectMeta{
				Namespace:  ns,
				Name:       name,
				Generation: 1,
			},
			Spec: apis.StreamSpec{
				Name:    name,
				MaxAge:  "1h",
				Storage: "memory",
			},
		})
		if err != nil {
			t.Fatal(err)
		}

		jc.PrependReactor("update", "streams", func(a k8stesting.Action) (handled bool, o runtime.Object, err error) {
			ua, ok := a.(k8stesting.UpdateAction)
			if !ok {
				return false, nil, nil
			}
			obj := ua.GetObject()

			str, ok := obj.(*apis.Stream)
			if !ok {
				t.Error("unexpected object type")
				t.Fatalf("got=%T; want=%T", obj, &apis.Stream{})
			}

			if got, want := len(str.Status.Conditions), 1; got != want {
				t.Error("unexpected number of conditions")
				t.Fatalf("got=%d; want=%d", got, want)
			}
			if got, want := str.Status.Conditions[0].Reason, "Errored"; got != want {
				t.Error("unexpected condition reason")
				t.Fatalf("got=%s; want=%s", got, want)
			}

			return true, obj, nil
		})

		jsmc := &mockJsmClient{
			loadStreamErr: errors.New("failed to load stream"),
		}
		if err := ctrl.processStream(ns, name, testWrapJSMC(jsmc)); err == nil {
			t.Fatal("unexpected success")
		}
	})
}


================================================
FILE: dependencies.md
================================================
# External Dependencies

This file lists the dependencies used in this repository.

| Dependency                           | License      |
|--------------------------------------|--------------|
| github.com/fsnotify/fsnotify         | BSD-3-Clause |
| github.com/nats-io/jsm.go            | Apache-2.0   |
| github.com/nats-io/nats.go           | Apache-2.0   |
| github.com/sirupsen/logrus           | MIT          |
| github.com/stretchr/testify          | MIT          |
| k8s.io/api                           | Apache-2.0   |
| k8s.io/apimachinery                  | Apache-2.0   |
| k8s.io/client-go                     | Apache-2.0   |
| k8s.io/code-generator                | Apache-2.0   |
| k8s.io/klog/v2                       | Apache-2.0   |
| sigs.k8s.io/structured-merge-diff/v4 | Apache-2.0   |


================================================
FILE: deploy/crds.yml
================================================
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: streams.jetstream.nats.io
spec:
  group: jetstream.nats.io
  scope: Namespaced
  names:
    kind: Stream
    singular: stream
    plural: streams
  versions:
  - name: v1beta2
    served: true
    storage: true
    subresources:
      status: {}
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              name:
                description: A unique name for the Stream.
                type: string
                pattern: '^[^.*>]*$'
                minLength: 1
              description:
                description: The description of the stream.
                type: string
              subjects:
                description: A list of subjects to consume, supports wildcards.
                type: array
                minLength: 1
                items:
                  type: string
                  minLength: 1
              retention:
                description: How messages are retained in the Stream, once this is exceeded old messages are removed.
                type: string
                enum:
                - limits
                - interest
                - workqueue
                default: limits
              maxConsumers:
                description: How many Consumers can be defined for a given Stream. -1 for unlimited.
                type: integer
                minimum: -1
                default: -1
              maxMsgs:
                description: How many messages may be in a Stream, oldest messages will be removed if the Stream exceeds this size. -1 for unlimited.
                type: integer
                minimum: -1
                default: -1
              maxBytes:
                description: How big the Stream may be, when the combined stream size exceeds this old messages are removed. -1 for unlimited.
                type: integer
                minimum: -1
                default: -1
              discard:
                description: When a Stream reach it's limits either old messages are deleted or new ones are denied.
                type: string
                enum:
                - old
                - new
                default: old
              discardPerSubject:
                description: Applies discard policy on a per-subject basis. Requires discard policy 'new' and 'maxMsgs' to be set.
                type: boolean
                default: false
              maxAge:
                description: Maximum age of any message in the stream, expressed in Go's time.Duration format. Empty for unlimited.
                type: string
                default: ''
              maxMsgsPerSubject:
                description: The maximum number of messages per subject.
                type: integer
                default: 0
              maxMsgSize:
                description: The largest message that will be accepted by the Stream. -1 for unlimited.
                type: integer
                minimum: -1
                default: -1
              storage:
                description: The storage backend to use for the Stream.
                type: string
                enum:
                - file
                - memory
                default: memory
              replicas:
                description: How many replicas to keep for each message.
                type: integer
                minimum: 1
                default: 1
              noAck:
                description: Disables acknowledging messages that are received by the Stream.
                type: boolean
                default: false
              duplicateWindow:
                description: The duration window to track duplicate messages for.
                type: string
              placement:
                description: A stream's placement.
                type: object
                properties:
                  cluster:
                    type: string
                  tags:
                    type: array
                    items:
                      type: string
              mirror:
                description: A stream mirror.
                type: object
                properties:
                  name:
                    type: string
                  optStartSeq:
                    type: integer
                  optStartTime:
                    description: Time format must be RFC3339.
                    type: string
                  filterSubject:
                    type: string
                  externalApiPrefix:
                    type: string
                  externalDeliverPrefix:
                    type: string
                  subjectTransforms:
                    description: List of subject transforms for this mirror.
                    type: array
                    items:
                      description: A subject transform pair.
                      type: object
                      properties:
                        source:
                          description: Source subject.
                          type: string
                        dest:
                          description: Destination subject.
                          type: string
              sources:
                description: A stream's sources.
                type: array
                items:
                  type: object
                  properties:
                    name:
                      type: string
                    optStartSeq:
                      type: integer
                    optStartTime:
                      description: Time format must be RFC3339.
                      type: string
                    filterSubject:
                      type: string
                    externalApiPrefix:
                      type: string
                    externalDeliverPrefix:
                      type: string
                    subjectTransforms:
                      description: List of subject transforms for this mirror.
                      type: array
                      items:
                        description: A subject transform pair.
                        type: object
                        properties:
                          source:
                            description: Source subject.
                            type: string
                          dest:
                            description: Destination subject.
                            type: string
              sealed:
                description: Seal an existing stream so no new messages may be added.
                type: boolean
                default: false
              denyDelete:
                description: When true, restricts the ability to delete messages from a stream via the API. Cannot be changed once set to true.
                type: boolean
                default: false
              denyPurge:
                description: When true, restricts the ability to purge a stream via the API. Cannot be changed once set to true.
                type: boolean
                default: false
              allowRollup:
                description: When true, allows the use of the Nats-Rollup header to replace all contents of a stream, or subject in a stream, with a single new message.
                type: boolean
                default: false
              compression:
                description: Stream specific compression.
                type: string
                enum:
                - s2
                - none
                - ''
                default: ''
              firstSequence:
                description: Sequence number from which the Stream will start.
                type: number
                default: 0
              subjectTransform:
                description: SubjectTransform is for applying a subject transform (to matching messages) when a new message is received.
                type: object
                properties:
                  source:
                    type: string
                    description: Source subject.
                  dest:
                    type: string
                    description: Destination subject to transform into.
              republish:
                description: Republish configuration of the stream.
                type: object
                properties:
                  destination:
                    type: string
                    description: Messages will be additionally published to this subject.
                  source:
                    type: string
                    description: Messages will be published from this subject to the destination subject.
              allowDirect:
                description: When true, allow higher performance, direct access to get individual messages.
                type: boolean
                default: false
              mirrorDirect:
                description: When true, enables direct access to messages from the origin stream.
                type: boolean
                default: false
              allowMsgTtl:
                description: When true, allows header initiated per-message TTLs. If disabled, then the `NATS-TTL` header will be ignored.
                type: boolean
                default: false
              subjectDeleteMarkerTtl:
                description: Enables and sets a duration for adding server markers for delete, purge and max age limits.
                type: string
                default: ''
              allowMsgCounter:
                description: When true, enables message counters for the stream.
                type: boolean
                default: false
              allowAtomicPublish:
                description: When true, enables atomic batch publishing.
                type: boolean
                default: false
              allowMsgSchedules:
                description: When true, enables message scheduling.
                type: boolean
                default: false
              persistMode:
                description: Configures stream persistence settings (async or default).
                type: string
                default: ''
              consumerLimits:
                type: object
                properties:
                  inactiveThreshold:
                    description: The duration of inactivity after which a consumer is considered inactive.
                    type: string
                  maxAckPending:
                    description: Maximum number of outstanding unacknowledged messages.
                    type: integer
              metadata:
                description: Additional Stream metadata.
                type: object
                additionalProperties:
                  type: string
              account:
                description: Name of the account to which the Stream belongs.
                type: string
                pattern: '^[^.*>]*$'
              creds:
                description: NATS user credentials for connecting to servers. Please make sure your controller has mounted the creds on this path.
                type: string
                default: ''
              nkey:
                description: NATS user NKey for connecting to servers.
                type: string
                default: ''
              preventDelete:
                description: When true, the managed Stream will not be deleted when the resource is deleted.
                type: boolean
                default: false
              preventUpdate:
                description: When true, the managed Stream will not be updated when the resource is updated.
                type: boolean
                default: false
              servers:
                description: A list of servers for creating stream.
                type: array
                items:
                  type: string
                default: []
              tls:
                description: A client's TLS certs and keys.
                type: object
                properties:
                  clientCert:
                    description: A client's cert filepath. Should be mounted.
                    type: string
                  clientKey:
                    description: A client's key filepath. Should be mounted.
                    type: string
                  rootCas:
                    description: A list of filepaths to CAs. Should be mounted.
                    type: array
                    items:
                      type: string
              tlsFirst:
                description: When true, the KV Store will initiate TLS before server INFO.
                type: boolean
                default: false
              jsDomain:
                description: The JetStream domain to use for the stream.
                type: string
          status:
            type: object
            properties:
              observedGeneration:
                type: integer
              conditions:
                type: array
                items:
                  type: object
                  properties:
                    type:
                      type: string
                    status:
                      type: string
                    lastTransitionTime:
                      type: string
                    reason:
                      type: string
                    message:
                      type: string
    additionalPrinterColumns:
    - name: State
      type: string
      description: The current state of the stream.
      jsonPath: .status.conditions[?(@.type == 'Ready')].reason
    - name: Stream Name
      type: string
      description: The name of the JetStream Stream.
      jsonPath: .spec.name
    - name: Subjects
      type: string
      description: The subjects this Stream produces.
      jsonPath: .spec.subjects
  - name: v1beta1
    served: false
    storage: false
    subresources:
      status: {}
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              name:
                description: A unique name for the Stream.
                type: string
                pattern: '^[^.*>]*$'
                minLength: 1
              subjects:
                description: A list of subjects to consume, supports wildcards.
                type: array
                minLength: 1
                items:
                  type: string
                  minLength: 1
              retention:
                description: How messages are retained in the Stream, once this is exceeded old messages are removed.
                type: string
                enum:
                - limits
                - interest
                - workqueue
                default: limits
              maxConsumers:
                description: How many Consumers can be defined for a given Stream. -1 for unlimited.
                type: integer
                minimum: -1
                default: -1
              maxMsgs:
                description: How many messages may be in a Stream, oldest messages will be removed if the Stream exceeds this size. -1 for unlimited.
                type: integer
                minimum: -1
                default: -1
              maxBytes:
                description: How big the Stream may be, when the combined stream size exceeds this old messages are removed. -1 for unlimited.
                type: integer
                minimum: -1
                default: -1
              maxAge:
                description: Maximum age of any message in the stream, expressed in Go's time.Duration format. Empty for unlimited.
                type: string
                default: ''
              maxMsgSize:
                description: The largest message that will be accepted by the Stream. -1 for unlimited.
                type: integer
                minimum: -1
                default: -1
              storage:
                description: The storage backend to use for the Stream.
                type: string
                enum:
                - file
                - memory
                default: memory
              replicas:
                description: How many replicas to keep for each message.
                type: integer
                minimum: 1
                default: 1
              noAck:
                description: Disables acknowledging messages that are received by the Stream.
                type: boolean
                default: false
              discard:
                description: When a Stream reach it's limits either old messages are deleted or new ones are denied.
                type: string
                enum:
                - old
                - new
                default: old
              duplicateWindow:
                description: The duration window to track duplicate messages for.
                type: string
              description:
                description: The description of the stream.
                type: string
              maxMsgsPerSubject:
                description: The maximum number of messages per subject.
                type: integer
                default: 0
              mirror:
                description: A stream mirror.
                type: object
                properties:
                  name:
                    type: string
                  optStartSeq:
                    type: integer
                  optStartTime:
                    description: Time format must be RFC3339.
                    type: string
                  filterSubject:
                    type: string
                  externalApiPrefix:
                    type: string
                  externalDeliverPrefix:
                    type: string
              placement:
                description: A stream's placement.
                type: object
                properties:
                  cluster:
                    type: string
                  tags:
                    type: array
                    items:
                      type: string
              sources:
                description: A stream's sources.
                type: array
                items:
                  type: object
                  properties:
                    name:
                      type: string
                    optStartSeq:
                      type: integer
                    optStartTime:
                      description: Time format must be RFC3339.
                      type: string
                    filterSubject:
                      type: string
                    externalApiPrefix:
                      type: string
                    externalDeliverPrefix:
                      type: string
          status:
            type: object
            properties:
              observedGeneration:
                type: integer
              conditions:
                type: array
                items:
                  type: object
                  properties:
                    type:
                      type: string
                    status:
                      type: string
                    lastTransitionTime:
                      type: string
                    reason:
                      type: string
                    message:
                      type: string
    additionalPrinterColumns:
    - name: State
      type: string
      description: The current state of the stream.
      jsonPath: .status.conditions[?(@.type == 'Ready')].reason
    - name: Stream Name
      type: string
      description: The name of the JetStream Stream.
      jsonPath: .spec.name
    - name: Subjects
      type: string
      description: The subjects this Stream produces.
      jsonPath: .spec.subjects
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: consumers.jetstream.nats.io
spec:
  group: jetstream.nats.io
  scope: Namespaced
  names:
    kind: Consumer
    singular: consumer
    plural: consumers
  versions:
  - name: v1beta2
    served: true
    storage: true
    subresources:
      status: {}
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              durableName:
                description: The name of the Consumer.
                type: string
                pattern: '^[^.*>]+$'
                minLength: 1
              streamName:
                description: The name of the Stream to create the Consumer in.
                type: string
              deliverPolicy:
                type: string
                enum:
                - all
                - last
                - new
                # Requires optStartSeq
                - byStartSequence
                # Requires optStartTime
                - byStartTime
                - lastPerSubject
                default: all
              optStartSeq:
                type: integer
                minimum: 0
              optStartTime:
                description: Time format must be RFC3339.
                type: string
              deliverSubject:
                description: The subject to deliver observed messages, when not set, a pull-based Consumer is created.
                type: string
              ackPolicy:
                description: How messages should be acknowledged.
                type: string
                enum:
                - none
                - all
                - explicit
                default: none
              ackWait:
                description: How long to allow messages to remain un-acknowledged before attempting redelivery.
                type: string
                default: 1ns
              maxDeliver:
                type: integer
                minimum: -1
              backoff:
                description: List of durations representing a retry time scale for NaK'd or retried messages.
                type: array
                items:
                  type: string
              filterSubject:
                description: Select only a specific incoming subjects, supports wildcards.
                type: string
              filterSubjects:
                description: List of incoming subjects, supports wildcards. Available since 2.10.
                type: array
                items:
                  type: string
              replayPolicy:
                description: How messages are sent.
                type: string
                enum:
                - instant
                - original
                default: instant
              sampleFreq:
                description: What percentage of acknowledgements should be samples for observability.
                type: string
              maxWaiting:
                description: The number of pulls that can be outstanding on a pull consumer, pulls received after this is reached are ignored.
                type: integer
              rateLimitBps:
                description: Rate at which messages will be delivered to clients, expressed in bit per second.
                type: integer
              maxAckPending:
                description: Maximum pending Acks before consumers are paused.
                type: integer
              deliverGroup:
                description: The name of a queue group.
                type: string
              description:
                description: The description of the consumer.
                type: string
              flowControl:
                description: Enables flow control.
                type: boolean
                default: false
              headersOnly:
                description: When set, only the headers of messages in the stream are delivered, and not the bodies. Additionally, Nats-Msg-Size header is added to indicate the size of the removed payload.
                type: boolean
                default: false
              heartbeatInterval:
                description: The interval used to deliver idle heartbeats for push-based consumers, in Go's time.Duration format.
                type: string
              maxRequestBatch:
                description: The largest batch property that may be specified when doing a pull on a Pull Consumer.
                type: integer
              maxRequestExpires:
                description: The maximum expires duration that may be set when doing a pull on a Pull Consumer.
                type: string
              maxRequestMaxBytes:
                description: The maximum max_bytes value that maybe set when dong a pull on a Pull Consumer.
                type: integer
              inactiveThreshold:
                description: The idle time an Ephemeral Consumer allows before it is removed.
                type: string
              pauseUntil:
                description: RFC3339 timestamp until which the consumer should be paused.
                type: string
                default: ''
              priorityPolicy:
                description: Priority policy for consumer (pinned_client, overflow, prioritized, or none).
                type: string
                default: ''
              pinnedTtl:
                description: TTL for pinned client when using pinned_client priority policy.
                type: string
                default: ''
              priorityGroups:
                description: List of priority groups for the consumer. For now, only one group is supported.
                type: array
                items:
                  type: string
              replicas:
                description: When set do not inherit the replica count from the stream but specifically set it to this amount.
                type: integer
              memStorage:
                description: Force the consumer state to be kept in memory rather than inherit the setting from the stream.
                type: boolean
                default: false
              metadata:
                description: Additional Consumer metadata.
                type: object
                additionalProperties:
                  type: string
              account:
                description: Name of the account to which the Consumer belongs.
                type: string
                pattern: '^[^.*>]*$'
              creds:
                description: NATS user credentials for connecting to servers. Please make sure your controller has mounted the creds on its path.
                type: string
                default: ''
              nkey:
                description: NATS user NKey for connecting to servers.
                type: string
                default: ''
              preventDelete:
                description: When true, the managed Consumer will not be deleted when the resource is deleted.
                type: boolean
                default: false
              preventUpdate:
                description: When true, the managed Consumer will not be updated when the resource is updated.
                type: boolean
                default: false
              servers:
                description: A list of servers for creating consumer.
                type: array
                items:
                  type: string
                default: []
              tls:
                description: A client's TLS certs and keys.
                type: object
                properties:
                  clientCert:
                    description: A client's cert filepath. Should be mounted.
                    type: string
                  clientKey:
                    description: A client's key filepath. Should be mounted.
                    type: string
                  rootCas:
                    description: A list of filepaths to CAs. Should be mounted.
                    type: array
                    items:
                      type: string
              tlsFirst:
                description: When true, the KV Store will initiate TLS before server INFO.
                type: boolean
                default: false
              jsDomain:
                description: The JetStream domain to use for the consumer.
                type: string
          status:
            type: object
            properties:
              observedGeneration:
                type: integer
              conditions:
                type: array
                items:
                  type: object
                  properties:
                    type:
                      type: string
                    status:
                      type: string
                    lastTransitionTime:
                      type: string
                    reason:
                      type: string
                    message:
                      type: string
    additionalPrinterColumns:
    - name: State
      type: string
      description: The current state of the consumer.
      jsonPath: .status.conditions[?(@.type == 'Ready')].reason
    - name: Stream
      type: string
      description: The name of the JetStream Stream.
      jsonPath: .spec.streamName
    - name: Consumer
      type: string
      description: The name of the JetStream Consumer.
      jsonPath: .spec.durableName
    - name: Ack Policy
      type: string
      description: The ack policy.
      jsonPath: .spec.ackPolicy
  - name: v1beta1
    served: false
    storage: false
    subresources:
      status: {}
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              streamName:
                description: The name of the Stream to create the Consumer in.
                type: string
              deliverPolicy:
                type: string
                enum:
                - all
                - last
                - new
                # Requires optStartSeq
                - byStartSequence
                # Requires optStartTime
                - byStartTime
                default: all
              optStartSeq:
                type: integer
                minimum: 0
              optStartTime:
                description: Time format must be RFC3339.
                type: string
              durableName:
                description: The name of the Consumer.
                type: string
                pattern: '^[^.*>]+$'
                minLength: 1
              deliverSubject:
                description: The subject to deliver observed messages, when not set, a pull-based Consumer is created.
                type: string
              ackPolicy:
                description: How messages should be acknowledged.
                type: string
                enum:
                - none
                - all
                - explicit
                default: none
              ackWait:
                description: How long to allow messages to remain un-acknowledged before attempting redelivery.
                type: string
                default: 1ns
              maxDeliver:
                type: integer
                minimum: -1
              filterSubject:
                description: Select only a specific incoming subjects, supports wildcards.
                type: string
              replayPolicy:
                description: How messages are sent.
                type: string
                enum:
                - instant
                - original
                default: instant
              sampleFreq:
                description: What percentage of acknowledgements should be samples for observability.
                type: string
              rateLimitBps:
                description: Rate at which messages will be delivered to clients, expressed in bit per second.
                type: integer
              maxAckPending:
                description: Maximum pending Acks before consumers are paused.
                type: integer
              deliverGroup:
                description: The name of a queue group.
                type: string
              description:
                description: The description of the consumer.
                type: string
              flowControl:
                description: Enables flow control.
                type: boolean
                default: false
              heartbeatInterval:
                description: The interval used to deliver idle heartbeats for push-based consumers, in Go's time.Duration fo
Download .txt
gitextract_mbhvqodb/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── config.yml
│   │   ├── defect.yml
│   │   └── proposal.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── claude.yml
│       ├── deps-release-detect.yaml
│       ├── deps-release-tag.yaml
│       ├── e2e.yaml
│       ├── release.yaml
│       └── test.yaml
├── .gitignore
├── .goreleaser.yml
├── CLAUDE.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── cicd/
│   ├── Dockerfile
│   ├── Dockerfile_goreleaser
│   ├── assets/
│   │   └── entrypoint.sh
│   └── tag-deps-version.txt
├── cmd/
│   ├── jetstream-controller/
│   │   └── main.go
│   ├── nats-boot-config/
│   │   └── main.go
│   └── nats-server-config-reloader/
│       └── main.go
├── controllers/
│   └── jetstream/
│       ├── conn_pool.go
│       ├── conn_pool_test.go
│       ├── consumer.go
│       ├── consumer_test.go
│       ├── controller.go
│       ├── controller_test.go
│       ├── jsmclient.go
│       ├── jsmclient_test.go
│       ├── stream.go
│       └── stream_test.go
├── dependencies.md
├── deploy/
│   ├── crds.yml
│   ├── examples/
│   │   ├── consumer_pull.yml
│   │   ├── consumer_push.yml
│   │   ├── stream.yml
│   │   ├── stream_mirror.yml
│   │   ├── stream_placement.yml
│   │   ├── stream_servers.yml
│   │   └── stream_sources.yml
│   └── rbac.yml
├── docker-bake.hcl
├── docs/
│   └── api.md
├── examples/
│   └── secure/
│       ├── client-tls.yaml
│       ├── issuer.yaml
│       ├── nack/
│       │   ├── account-foo.yaml
│       │   ├── nats-account-a.yaml
│       │   ├── nats-consumer-bar-a.yaml
│       │   ├── nats-stream-foo-a.yaml
│       │   └── stream-foo.yaml
│       ├── nack-a-client-tls.yaml
│       ├── nack-b-client-tls.yaml
│       ├── nats-helm.yaml
│       └── server-tls.yaml
├── go.mod
├── go.sum
├── internal/
│   └── controller/
│       ├── account_controller.go
│       ├── account_controller_test.go
│       ├── client.go
│       ├── connection_pool.go
│       ├── connection_pool_test.go
│       ├── consumer_controller.go
│       ├── consumer_controller_test.go
│       ├── helpers_test.go
│       ├── jetstream_controller.go
│       ├── jetstream_controller_test.go
│       ├── keyvalue_controller.go
│       ├── keyvalue_controller_test.go
│       ├── objectstore_controller.go
│       ├── objectstore_controller_test.go
│       ├── register.go
│       ├── stream_controller.go
│       ├── stream_controller_test.go
│       ├── suite_test.go
│       └── types.go
├── kuttl-test.yaml
├── pkg/
│   ├── bootconfig/
│   │   └── bootconfig.go
│   ├── jetstream/
│   │   ├── apis/
│   │   │   └── jetstream/
│   │   │       ├── register.go
│   │   │       ├── v1beta1/
│   │   │       │   ├── consumertypes.go
│   │   │       │   ├── doc.go
│   │   │       │   ├── register.go
│   │   │       │   ├── streamtemplatetypes.go
│   │   │       │   ├── streamtypes.go
│   │   │       │   ├── types.go
│   │   │       │   └── zz_generated.deepcopy.go
│   │   │       └── v1beta2/
│   │   │           ├── accounttypes.go
│   │   │           ├── consumertypes.go
│   │   │           ├── doc.go
│   │   │           ├── keyvaluetypes.go
│   │   │           ├── objectstoretypes.go
│   │   │           ├── register.go
│   │   │           ├── streamtypes.go
│   │   │           ├── types.go
│   │   │           └── zz_generated.deepcopy.go
│   │   └── generated/
│   │       ├── applyconfiguration/
│   │       │   ├── internal/
│   │       │   │   └── internal.go
│   │       │   ├── jetstream/
│   │       │   │   └── v1beta2/
│   │       │   │       ├── account.go
│   │       │   │       ├── accountspec.go
│   │       │   │       ├── basestreamconfig.go
│   │       │   │       ├── condition.go
│   │       │   │       ├── connectionopts.go
│   │       │   │       ├── consumer.go
│   │       │   │       ├── consumerlimits.go
│   │       │   │       ├── consumerspec.go
│   │       │   │       ├── credssecret.go
│   │       │   │       ├── keyvalue.go
│   │       │   │       ├── keyvaluespec.go
│   │       │   │       ├── nkeysecret.go
│   │       │   │       ├── objectstore.go
│   │       │   │       ├── objectstorespec.go
│   │       │   │       ├── republish.go
│   │       │   │       ├── secretref.go
│   │       │   │       ├── status.go
│   │       │   │       ├── stream.go
│   │       │   │       ├── streamplacement.go
│   │       │   │       ├── streamsource.go
│   │       │   │       ├── streamspec.go
│   │       │   │       ├── subjecttransform.go
│   │       │   │       ├── tls.go
│   │       │   │       ├── tlssecret.go
│   │       │   │       ├── tokensecret.go
│   │       │   │       └── user.go
│   │       │   └── utils.go
│   │       ├── clientset/
│   │       │   └── versioned/
│   │       │       ├── clientset.go
│   │       │       ├── fake/
│   │       │       │   ├── clientset_generated.go
│   │       │       │   ├── doc.go
│   │       │       │   └── register.go
│   │       │       ├── scheme/
│   │       │       │   ├── doc.go
│   │       │       │   └── register.go
│   │       │       └── typed/
│   │       │           └── jetstream/
│   │       │               └── v1beta2/
│   │       │                   ├── account.go
│   │       │                   ├── consumer.go
│   │       │                   ├── doc.go
│   │       │                   ├── fake/
│   │       │                   │   ├── doc.go
│   │       │                   │   ├── fake_account.go
│   │       │                   │   ├── fake_consumer.go
│   │       │                   │   ├── fake_jetstream_client.go
│   │       │                   │   ├── fake_keyvalue.go
│   │       │                   │   ├── fake_objectstore.go
│   │       │                   │   └── fake_stream.go
│   │       │                   ├── generated_expansion.go
│   │       │                   ├── jetstream_client.go
│   │       │                   ├── keyvalue.go
│   │       │                   ├── objectstore.go
│   │       │                   └── stream.go
│   │       ├── informers/
│   │       │   └── externalversions/
│   │       │       ├── factory.go
│   │       │       ├── generic.go
│   │       │       ├── internalinterfaces/
│   │       │       │   └── factory_interfaces.go
│   │       │       └── jetstream/
│   │       │           ├── interface.go
│   │       │           └── v1beta2/
│   │       │               ├── account.go
│   │       │               ├── consumer.go
│   │       │               ├── interface.go
│   │       │               ├── keyvalue.go
│   │       │               ├── objectstore.go
│   │       │               └── stream.go
│   │       └── listers/
│   │           └── jetstream/
│   │               └── v1beta2/
│   │                   ├── account.go
│   │                   ├── consumer.go
│   │                   ├── expansion_generated.go
│   │                   ├── keyvalue.go
│   │                   ├── objectstore.go
│   │                   └── stream.go
│   ├── k8scodegen/
│   │   ├── file-header.txt
│   │   └── k8scodegen.go
│   └── natsreloader/
│       ├── natsreloader.go
│       └── natsreloader_test.go
└── tests/
    ├── Dockerfile
    ├── nack-control-loop.yaml
    ├── nack-legacy.yaml
    ├── nats.yaml
    └── stream-creation/
        ├── 00-nack.yaml
        ├── 01-stream.yaml
        ├── 02-natscli-stream.yaml
        ├── asserted-natscli.yaml
        ├── asserted-rides-stream.yaml
        ├── natscli.yaml
        └── rides-stream.yaml
Download .txt
SYMBOL INDEX (916 symbols across 110 files)

FILE: cmd/jetstream-controller/main.go
  function main (line 51) | func main() {
  function run (line 58) | func run() error {
  function runControlLoop (line 174) | func runControlLoop(config *rest.Config, natsCfg *controller.NatsConfig,...
  function handleSignals (line 241) | func handleSignals(cancel context.CancelFunc) {

FILE: cmd/nats-boot-config/main.go
  function main (line 32) | func main() {

FILE: cmd/nats-server-config-reloader/main.go
  type StringSet (line 24) | type StringSet
    method String (line 26) | func (s *StringSet) String() string {
    method Set (line 31) | func (s *StringSet) Set(val string) error {
  function main (line 36) | func main() {

FILE: controllers/jetstream/conn_pool.go
  type natsContext (line 16) | type natsContext struct
    method copy (line 31) | func (c *natsContext) copy() *natsContext {
    method hash (line 39) | func (c *natsContext) hash() (string, error) {
  type natsContextDefaults (line 86) | type natsContextDefaults struct
  type pooledNatsConn (line 95) | type pooledNatsConn struct
    method ReturnToPool (line 103) | func (pc *pooledNatsConn) ReturnToPool() {
  type natsConnPool (line 118) | type natsConnPool struct
    method Get (line 140) | func (cp *natsConnPool) Get(cfg *natsContext) (*pooledNatsConn, error) {
    method getPooledConn (line 194) | func (cp *natsConnPool) getPooledConn(key string, cfg *natsContext) (*...
  function newNatsConnPool (line 127) | func newNatsConnPool(logger *logrus.Logger, natsDefaults *natsContextDef...
  constant getPooledConnMaxTries (line 137) | getPooledConnMaxTries = 10

FILE: controllers/jetstream/conn_pool_test.go
  function TestConnPool (line 15) | func TestConnPool(t *testing.T) {

FILE: controllers/jetstream/consumer.go
  method runConsumerQueue (line 21) | func (c *Controller) runConsumerQueue() {
  method processConsumer (line 27) | func (c *Controller) processConsumer(ns, name string, jsmClient jsmClien...
  method processConsumerObject (line 38) | func (c *Controller) processConsumerObject(cns *apis.Consumer, jsm jsmCl...
  function consumerExists (line 144) | func consumerExists(ctx context.Context, c jsmClient, spec apis.Consumer...
  function createConsumer (line 155) | func createConsumer(ctx context.Context, c jsmClient, spec apis.Consumer...
  function updateConsumer (line 170) | func updateConsumer(ctx context.Context, c jsmClient, spec apis.Consumer...
  function consumerSpecToOpts (line 191) | func consumerSpecToOpts(spec apis.ConsumerSpec) ([]jsm.ConsumerOption, e...
  function deleteConsumer (line 368) | func deleteConsumer(ctx context.Context, c jsmClient, spec apis.Consumer...
  function setConsumerOK (line 392) | func setConsumerOK(ctx context.Context, s *apis.Consumer, i typed.Consum...
  function setConsumerErrored (line 418) | func setConsumerErrored(ctx context.Context, s *apis.Consumer, sif typed...

FILE: controllers/jetstream/consumer_test.go
  function TestProcessConsumer (line 23) | func TestProcessConsumer(t *testing.T) {
  function TestConsumerSpecToOpts (line 333) | func TestConsumerSpecToOpts(t *testing.T) {
  function testWrapJSMC (line 448) | func testWrapJSMC(jsm jsmClient) jsmClientFunc {

FILE: controllers/jetstream/controller.go
  constant maxQueueRetries (line 58) | maxQueueRetries = 10
  constant readyCondType (line 61) | readyCondType = "Ready"
  type Options (line 64) | type Options struct
  type Controller (line 89) | type Controller struct
    method Run (line 235) | func (c *Controller) Run() error {
    method RealJSMC (line 311) | func (c *Controller) RealJSMC(cfg *natsContext) (jsmClient, error) {
    method cleanupStreams (line 345) | func (c *Controller) cleanupStreams() error {
    method cleanupConsumers (line 415) | func (c *Controller) cleanupConsumers() error {
    method normalEvent (line 467) | func (c *Controller) normalEvent(o runtime.Object, reason, message str...
    method warningEvent (line 473) | func (c *Controller) warningEvent(o runtime.Object, reason, message st...
    method getAccountOverrides (line 491) | func (c *Controller) getAccountOverrides(account string, ns string) (*...
    method runWithJsmc (line 628) | func (c *Controller) runWithJsmc(jsm jsmClientFunc, acc *accountOverri...
  function NewController (line 122) | func NewController(opt Options) *Controller {
  function selectMissingStreamsFromList (line 327) | func selectMissingStreamsFromList(prev, cur map[string]*apis.Stream) []*...
  function streamsMap (line 337) | func streamsMap(ss []*apis.Stream) map[string]*apis.Stream {
  function selectMissingConsumersFromList (line 397) | func selectMissingConsumersFromList(prev, cur map[string]*apis.Consumer)...
  function consumerMap (line 407) | func consumerMap(cs []*apis.Consumer) map[string]*apis.Consumer {
  type accountOverrides (line 479) | type accountOverrides struct
  type jsmcSpecOverrides (line 621) | type jsmcSpecOverrides struct
  function splitNamespaceName (line 691) | func splitNamespaceName(item interface{}) (ns string, name string, err e...
  function getStorageType (line 711) | func getStorageType(s string) (jsmapi.StorageType, error) {
  function enqueueWork (line 722) | func enqueueWork(q workqueue.TypedRateLimitingInterface[any], item inter...
  type jsmClientFunc (line 733) | type jsmClientFunc
  type processorFunc (line 734) | type processorFunc
  function processQueueNext (line 737) | func processQueueNext(q workqueue.TypedRateLimitingInterface[any], jmsCl...
  function UpsertCondition (line 772) | func UpsertCondition(cs []apis.Condition, next apis.Condition) []apis.Co...
  function shouldEnqueue (line 785) | func shouldEnqueue(prevObj, nextObj interface{}) bool {
  function eventHandlers (line 807) | func eventHandlers(q workqueue.TypedRateLimitingInterface[any]) cache.Re...

FILE: controllers/jetstream/controller_test.go
  function TestMain (line 19) | func TestMain(m *testing.M) {
  function TestGetStorageType (line 28) | func TestGetStorageType(t *testing.T) {
  function TestEnqueueWork (line 63) | func TestEnqueueWork(t *testing.T) {
  function TestProcessQueueNext (line 94) | func TestProcessQueueNext(t *testing.T) {
  function TestUpsertCondition (line 184) | func TestUpsertCondition(t *testing.T) {
  function TestShouldEnqueue (line 238) | func TestShouldEnqueue(t *testing.T) {

FILE: controllers/jetstream/jsmclient.go
  type jsmClient (line 12) | type jsmClient interface
  type jsmStream (line 23) | type jsmStream interface
  type jsmConsumer (line 28) | type jsmConsumer interface
  type realJsmClient (line 33) | type realJsmClient struct
    method Connect (line 38) | func (c *realJsmClient) Connect(servers string, opts ...nats.Option) e...
    method Close (line 55) | func (c *realJsmClient) Close() {
    method LoadStream (line 59) | func (c *realJsmClient) LoadStream(_ context.Context, name string) (js...
    method NewStream (line 63) | func (c *realJsmClient) NewStream(_ context.Context, name string, opts...
    method LoadConsumer (line 67) | func (c *realJsmClient) LoadConsumer(_ context.Context, stream, consum...
    method NewConsumer (line 71) | func (c *realJsmClient) NewConsumer(_ context.Context, stream string, ...

FILE: controllers/jetstream/jsmclient_test.go
  type mockStream (line 11) | type mockStream struct
    method UpdateConfiguration (line 17) | func (m *mockStream) UpdateConfiguration(cnf jsmapi.StreamConfig, opts...
    method Delete (line 27) | func (m *mockStream) Delete() error {
  type mockConsumer (line 31) | type mockConsumer struct
    method UpdateConfiguration (line 35) | func (m *mockConsumer) UpdateConfiguration(opts ...jsm.ConsumerOption)...
    method Delete (line 39) | func (m *mockConsumer) Delete() error {
  type mockJsmClient (line 43) | type mockJsmClient struct
    method Connect (line 57) | func (c *mockJsmClient) Connect(servers string, opts ...nats.Option) e...
    method Close (line 61) | func (c *mockJsmClient) Close() {}
    method LoadStream (line 63) | func (c *mockJsmClient) LoadStream(ctx context.Context, name string) (...
    method NewStream (line 67) | func (c *mockJsmClient) NewStream(ctx context.Context, name string, op...
    method LoadConsumer (line 71) | func (c *mockJsmClient) LoadConsumer(ctx context.Context, stream, cons...
    method NewConsumer (line 75) | func (c *mockJsmClient) NewConsumer(ctx context.Context, stream string...

FILE: controllers/jetstream/stream.go
  method runStreamQueue (line 33) | func (c *Controller) runStreamQueue() {
  method processStream (line 39) | func (c *Controller) processStream(ns, name string, jsm jsmClientFunc) (...
  method processStreamObject (line 50) | func (c *Controller) processStreamObject(str *apis.Stream, jsm jsmClient...
  function streamExists (line 161) | func streamExists(ctx context.Context, c jsmClient, spec apis.StreamSpec...
  function createStream (line 172) | func createStream(ctx context.Context, c jsmClient, spec apis.StreamSpec...
  function updateStream (line 377) | func updateStream(ctx context.Context, c jsmClient, spec apis.StreamSpec...
  function deleteStream (line 497) | func deleteStream(ctx context.Context, c jsmClient, spec apis.StreamSpec...
  function setStreamErrored (line 521) | func setStreamErrored(ctx context.Context, s *apis.Stream, sif typed.Str...
  function setStreamOK (line 552) | func setStreamOK(ctx context.Context, s *apis.Stream, i typed.StreamInte...
  function getDurationFromString (line 581) | func getDurationFromString(v string) (time.Duration, error) {
  function getRetention (line 589) | func getRetention(v string) jsmapi.RetentionPolicy {
  function getStorage (line 600) | func getStorage(v string) jsmapi.StorageType {
  function getDiscard (line 609) | func getDiscard(v string) jsmapi.DiscardPolicy {
  function getDuplicates (line 618) | func getDuplicates(v string) (time.Duration, error) {
  function getStreamSource (line 626) | func getStreamSource(ss *apis.StreamSource) (*jsmapi.StreamSource, error) {

FILE: controllers/jetstream/stream_test.go
  function TestProcessStream (line 21) | func TestProcessStream(t *testing.T) {

FILE: internal/controller/account_controller.go
  type AccountReconciler (line 40) | type AccountReconciler struct
    method Reconcile (line 62) | func (r *AccountReconciler) Reconcile(ctx context.Context, req ctrl.Re...
    method findDependentResources (line 159) | func (r *AccountReconciler) findDependentResources(ctx context.Context...
    method SetupWithManager (line 224) | func (r *AccountReconciler) SetupWithManager(mgr ctrl.Manager) error {
  type JetStreamResource (line 45) | type JetStreamResource interface
  type JetStreamResourceList (line 50) | type JetStreamResourceList

FILE: internal/controller/client.go
  type NatsConfig (line 15) | type NatsConfig struct
    method Copy (line 30) | func (o *NatsConfig) Copy() *NatsConfig {
    method Hash (line 39) | func (o *NatsConfig) Hash() (string, error) {
    method Overlay (line 92) | func (o *NatsConfig) Overlay(overlay *NatsConfig) {
    method HasAuth (line 136) | func (o *NatsConfig) HasAuth() bool {
    method UnsetAuth (line 140) | func (o *NatsConfig) UnsetAuth() {
    method buildOptions (line 149) | func (o *NatsConfig) buildOptions() ([]nats.Option, error) {
  type Closable (line 195) | type Closable interface
  function CreateJSMClient (line 199) | func CreateJSMClient(conn *pooledConnection, pedantic bool, domain strin...
  function CreateJetStreamClient (line 233) | func CreateJetStreamClient(conn *pooledConnection, pedantic bool, domain...
  function createNatsConn (line 251) | func createNatsConn(cfg *NatsConfig) (*nats.Conn, error) {

FILE: internal/controller/connection_pool.go
  type pooledConnection (line 10) | type pooledConnection struct
    method Close (line 17) | func (pc *pooledConnection) Close() {
  type connectionPool (line 25) | type connectionPool struct
    method Get (line 38) | func (p *connectionPool) Get(c *NatsConfig, pedantic bool) (*pooledCon...
    method release (line 73) | func (p *connectionPool) release(hash string) {
  function newConnPool (line 31) | func newConnPool(gracePeriod time.Duration) *connectionPool {

FILE: internal/controller/connection_pool_test.go
  function TestConnPool (line 12) | func TestConnPool(t *testing.T) {

FILE: internal/controller/consumer_controller.go
  type ConsumerReconciler (line 46) | type ConsumerReconciler struct
    method Reconcile (line 57) | func (r *ConsumerReconciler) Reconcile(ctx context.Context, req ctrl.R...
    method deleteConsumer (line 139) | func (r *ConsumerReconciler) deleteConsumer(ctx context.Context, log l...
    method createOrUpdate (line 196) | func (r *ConsumerReconciler) createOrUpdate(ctx context.Context, log k...
    method SetupWithManager (line 525) | func (r *ConsumerReconciler) SetupWithManager(mgr ctrl.Manager) error {
  function getStoredConsumerState (line 311) | func getStoredConsumerState(consumer *api.Consumer) (*jsmapi.ConsumerCon...
  function getServerConsumerState (line 325) | func getServerConsumerState(js *jsm.Manager, consumer *api.Consumer) (*j...
  function consumerSpecToConfig (line 338) | func consumerSpecToConfig(spec *api.ConsumerSpec) ([]jsm.ConsumerOption,...

FILE: internal/controller/consumer_controller_test.go
  function Test_consumerSpecToConfig (line 726) | func Test_consumerSpecToConfig(t *testing.T) {

FILE: internal/controller/helpers_test.go
  function assertReadyStateMatches (line 15) | func assertReadyStateMatches(condition api.Condition, status v1.Conditio...
  function CreateTestServer (line 29) | func CreateTestServer() *server.Server {

FILE: internal/controller/jetstream_controller.go
  constant JSConsumerNotFoundErr (line 29) | JSConsumerNotFoundErr uint16 = 10014
  constant JSStreamNotFoundErr (line 30) | JSStreamNotFoundErr   uint16 = 10059
  type JetStreamController (line 35) | type JetStreamController interface
  function NewJSController (line 58) | func NewJSController(k8sClient client.Client, natsConfig *NatsConfig, co...
  type jsController (line 68) | type jsController struct
    method RequeueInterval (line 77) | func (c *jsController) RequeueInterval() time.Duration {
    method ReadOnly (line 89) | func (c *jsController) ReadOnly() bool {
    method ValidNamespace (line 93) | func (c *jsController) ValidNamespace(namespace string) bool {
    method WithJSMClient (line 98) | func (c *jsController) WithJSMClient(opts api.ConnectionOpts, ns strin...
    method WithJetStreamClient (line 118) | func (c *jsController) WithJetStreamClient(opts api.ConnectionOpts, ns...
    method natsConfigFromOpts (line 139) | func (c *jsController) natsConfigFromOpts(opts api.ConnectionOpts, ns ...
  function natsConfigFromOpts (line 392) | func natsConfigFromOpts(opts api.ConnectionOpts) *NatsConfig {
  function updateReadyCondition (line 432) | func updateReadyCondition(conditions []api.Condition, status v1.Conditio...
  function jsonString (line 464) | func jsonString(v string) []byte {
  function compareConfigState (line 468) | func compareConfigState(actual any, desired any) string {
  function versionComponents (line 472) | func versionComponents(version string) (major, minor, patch int, err err...

FILE: internal/controller/jetstream_controller_test.go
  function Test_updateReadyCondition (line 12) | func Test_updateReadyCondition(t *testing.T) {

FILE: internal/controller/keyvalue_controller.go
  constant kvStreamPrefix (line 40) | kvStreamPrefix = "KV_"
  type KeyValueReconciler (line 44) | type KeyValueReconciler struct
    method Reconcile (line 60) | func (r *KeyValueReconciler) Reconcile(ctx context.Context, req ctrl.R...
    method deleteKeyValue (line 135) | func (r *KeyValueReconciler) deleteKeyValue(ctx context.Context, log l...
    method createOrUpdate (line 185) | func (r *KeyValueReconciler) createOrUpdate(ctx context.Context, log l...
    method SetupWithManager (line 400) | func (r *KeyValueReconciler) SetupWithManager(mgr ctrl.Manager) error {
  function getStoredKeyValueState (line 301) | func getStoredKeyValueState(keyValue *api.KeyValue) (*jetstream.StreamCo...
  function getServerKeyValueState (line 315) | func getServerKeyValueState(ctx context.Context, js jetstream.JetStream,...
  function keyValueSpecToConfig (line 328) | func keyValueSpecToConfig(spec *api.KeyValueSpec) (jetstream.KeyValueCon...

FILE: internal/controller/keyvalue_controller_test.go
  function Test_mapKVSpecToConfig (line 685) | func Test_mapKVSpecToConfig(t *testing.T) {

FILE: internal/controller/objectstore_controller.go
  constant objStreamPrefix (line 40) | objStreamPrefix = "OBJ_"
  type ObjectStoreReconciler (line 44) | type ObjectStoreReconciler struct
    method Reconcile (line 61) | func (r *ObjectStoreReconciler) Reconcile(ctx context.Context, req ctr...
    method deleteObjectStore (line 133) | func (r *ObjectStoreReconciler) deleteObjectStore(ctx context.Context,...
    method createOrUpdate (line 183) | func (r *ObjectStoreReconciler) createOrUpdate(ctx context.Context, lo...
    method SetupWithManager (line 366) | func (r *ObjectStoreReconciler) SetupWithManager(mgr ctrl.Manager) err...
  function getStoredObjectStoreState (line 299) | func getStoredObjectStoreState(objectStore *api.ObjectStore) (*jetstream...
  function getServerObjectStoreState (line 313) | func getServerObjectStoreState(ctx context.Context, js jetstream.JetStre...
  function objectStoreSpecToConfig (line 326) | func objectStoreSpecToConfig(spec *api.ObjectStoreSpec) (jetstream.Objec...

FILE: internal/controller/objectstore_controller_test.go
  function Test_mapobjectstoreSpecToConfig (line 675) | func Test_mapobjectstoreSpecToConfig(t *testing.T) {

FILE: internal/controller/register.go
  type Config (line 15) | type Config struct
  function RegisterAll (line 26) | func RegisterAll(mgr ctrl.Manager, clientConfig *NatsConfig, config *Con...

FILE: internal/controller/stream_controller.go
  type StreamReconciler (line 42) | type StreamReconciler struct
    method Reconcile (line 59) | func (r *StreamReconciler) Reconcile(ctx context.Context, req ctrl.Req...
    method deleteStream (line 134) | func (r *StreamReconciler) deleteStream(ctx context.Context, log logr....
    method createOrUpdate (line 184) | func (r *StreamReconciler) createOrUpdate(ctx context.Context, log log...
    method SetupWithManager (line 649) | func (r *StreamReconciler) SetupWithManager(mgr ctrl.Manager) error {
  function getStoredStreamState (line 299) | func getStoredStreamState(stream *api.Stream) (*jsmapi.StreamConfig, err...
  function getServerStreamState (line 313) | func getServerStreamState(jsm *jsm.Manager, stream *api.Stream) (*jsmapi...
  function streamSpecToConfig (line 326) | func streamSpecToConfig(spec *api.StreamSpec, currentConfig *jsmapi.Stre...
  function mapStreamSource (line 578) | func mapStreamSource(ss *api.StreamSource) (*jetstream.StreamSource, err...
  function mapJSMStreamSource (line 613) | func mapJSMStreamSource(ss *api.StreamSource) (*jsmapi.StreamSource, err...

FILE: internal/controller/stream_controller_test.go
  function Test_mapSpecToConfig (line 729) | func Test_mapSpecToConfig(t *testing.T) {
  function TestStreamUpdateWithoutPlacement (line 947) | func TestStreamUpdateWithoutPlacement(t *testing.T) {

FILE: internal/controller/suite_test.go
  function TestControllers (line 55) | func TestControllers(t *testing.T) {

FILE: internal/controller/types.go
  constant readyCondType (line 4) | readyCondType        = "Ready"
  constant accountFinalizer (line 5) | accountFinalizer     = "account.nats.io/finalizer"
  constant streamFinalizer (line 6) | streamFinalizer      = "stream.nats.io/finalizer"
  constant keyValueFinalizer (line 7) | keyValueFinalizer    = "kv.nats.io/finalizer"
  constant objectStoreFinalizer (line 8) | objectStoreFinalizer = "objectstore.nats.io/finalizer"
  constant consumerFinalizer (line 9) | consumerFinalizer    = "consumer.nats.io/finalizer"
  constant stateAnnotationConsumer (line 11) | stateAnnotationConsumer = "consumer.nats.io/state"
  constant stateAnnotationKV (line 12) | stateAnnotationKV       = "kv.nats.io/state"
  constant stateAnnotationObj (line 13) | stateAnnotationObj      = "objectstore.nats.io/state"
  constant stateAnnotationStream (line 14) | stateAnnotationStream   = "stream.nats.io/state"
  constant stateReady (line 16) | stateReady       = "Ready"
  constant stateReconciling (line 17) | stateReconciling = "Reconciling"
  constant stateErrored (line 18) | stateErrored     = "Errored"
  constant stateFinalizing (line 19) | stateFinalizing  = "Finalizing"

FILE: pkg/bootconfig/bootconfig.go
  type Options (line 29) | type Options struct
  type Controller (line 47) | type Controller struct
    method SetupClients (line 67) | func (c *Controller) SetupClients(cfg *k8srestapi.Config) error {
    method Run (line 77) | func (c *Controller) Run(ctx context.Context) error {
  function NewController (line 59) | func NewController(opts *Options) *Controller {

FILE: pkg/jetstream/apis/jetstream/register.go
  constant GroupName (line 5) | GroupName = "jetstream.nats.io"

FILE: pkg/jetstream/apis/jetstream/v1beta1/consumertypes.go
  type Consumer (line 11) | type Consumer struct
    method GetSpec (line 19) | func (c *Consumer) GetSpec() interface{} {
  type ConsumerSpec (line 24) | type ConsumerSpec struct
  type ConsumerList (line 49) | type ConsumerList struct

FILE: pkg/jetstream/apis/jetstream/v1beta1/register.go
  function Kind (line 22) | func Kind(kind string) schema.GroupKind {
  function Resource (line 27) | func Resource(resource string) schema.GroupResource {
  function addKnownTypes (line 32) | func addKnownTypes(scheme *runtime.Scheme) error {

FILE: pkg/jetstream/apis/jetstream/v1beta1/streamtemplatetypes.go
  type StreamTemplate (line 11) | type StreamTemplate struct
    method GetSpec (line 19) | func (s *StreamTemplate) GetSpec() interface{} {
  type StreamTemplateSpec (line 24) | type StreamTemplateSpec struct
  type StreamTemplateList (line 33) | type StreamTemplateList struct

FILE: pkg/jetstream/apis/jetstream/v1beta1/streamtypes.go
  type Stream (line 11) | type Stream struct
    method GetSpec (line 19) | func (s *Stream) GetSpec() interface{} {
  type StreamSpec (line 24) | type StreamSpec struct
  type StreamPlacement (line 47) | type StreamPlacement struct
  type StreamSource (line 52) | type StreamSource struct
  type StreamList (line 65) | type StreamList struct

FILE: pkg/jetstream/apis/jetstream/v1beta1/types.go
  type CredentialsSecret (line 7) | type CredentialsSecret struct
  type Status (line 12) | type Status struct
  type Condition (line 17) | type Condition struct

FILE: pkg/jetstream/apis/jetstream/v1beta1/zz_generated.deepcopy.go
  method DeepCopyInto (line 26) | func (in *Condition) DeepCopyInto(out *Condition) {
  method DeepCopy (line 32) | func (in *Condition) DeepCopy() *Condition {
  method DeepCopyInto (line 42) | func (in *Consumer) DeepCopyInto(out *Consumer) {
  method DeepCopy (line 52) | func (in *Consumer) DeepCopy() *Consumer {
  method DeepCopyObject (line 62) | func (in *Consumer) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 70) | func (in *ConsumerList) DeepCopyInto(out *ConsumerList) {
  method DeepCopy (line 85) | func (in *ConsumerList) DeepCopy() *ConsumerList {
  method DeepCopyObject (line 95) | func (in *ConsumerList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 103) | func (in *ConsumerSpec) DeepCopyInto(out *ConsumerSpec) {
  method DeepCopy (line 109) | func (in *ConsumerSpec) DeepCopy() *ConsumerSpec {
  method DeepCopyInto (line 119) | func (in *CredentialsSecret) DeepCopyInto(out *CredentialsSecret) {
  method DeepCopy (line 125) | func (in *CredentialsSecret) DeepCopy() *CredentialsSecret {
  method DeepCopyInto (line 135) | func (in *Status) DeepCopyInto(out *Status) {
  method DeepCopy (line 146) | func (in *Status) DeepCopy() *Status {
  method DeepCopyInto (line 156) | func (in *Stream) DeepCopyInto(out *Stream) {
  method DeepCopy (line 166) | func (in *Stream) DeepCopy() *Stream {
  method DeepCopyObject (line 176) | func (in *Stream) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 184) | func (in *StreamList) DeepCopyInto(out *StreamList) {
  method DeepCopy (line 199) | func (in *StreamList) DeepCopy() *StreamList {
  method DeepCopyObject (line 209) | func (in *StreamList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 217) | func (in *StreamPlacement) DeepCopyInto(out *StreamPlacement) {
  method DeepCopy (line 228) | func (in *StreamPlacement) DeepCopy() *StreamPlacement {
  method DeepCopyInto (line 238) | func (in *StreamSource) DeepCopyInto(out *StreamSource) {
  method DeepCopy (line 244) | func (in *StreamSource) DeepCopy() *StreamSource {
  method DeepCopyInto (line 254) | func (in *StreamSpec) DeepCopyInto(out *StreamSpec) {
  method DeepCopy (line 286) | func (in *StreamSpec) DeepCopy() *StreamSpec {
  method DeepCopyInto (line 296) | func (in *StreamTemplate) DeepCopyInto(out *StreamTemplate) {
  method DeepCopy (line 306) | func (in *StreamTemplate) DeepCopy() *StreamTemplate {
  method DeepCopyObject (line 316) | func (in *StreamTemplate) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 324) | func (in *StreamTemplateList) DeepCopyInto(out *StreamTemplateList) {
  method DeepCopy (line 339) | func (in *StreamTemplateList) DeepCopy() *StreamTemplateList {
  method DeepCopyObject (line 349) | func (in *StreamTemplateList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 357) | func (in *StreamTemplateSpec) DeepCopyInto(out *StreamTemplateSpec) {
  method DeepCopy (line 364) | func (in *StreamTemplateSpec) DeepCopy() *StreamTemplateSpec {

FILE: pkg/jetstream/apis/jetstream/v1beta2/accounttypes.go
  type Account (line 11) | type Account struct
    method GetSpec (line 19) | func (c *Account) GetSpec() interface{} {
  type AccountSpec (line 24) | type AccountSpec struct
  type AccountList (line 36) | type AccountList struct

FILE: pkg/jetstream/apis/jetstream/v1beta2/consumertypes.go
  type Consumer (line 11) | type Consumer struct
    method GetSpec (line 19) | func (c *Consumer) GetSpec() interface{} {
  type ConsumerSpec (line 24) | type ConsumerSpec struct
  type ConsumerList (line 65) | type ConsumerList struct

FILE: pkg/jetstream/apis/jetstream/v1beta2/keyvaluetypes.go
  type KeyValue (line 13) | type KeyValue struct
    method GetSpec (line 21) | func (s *KeyValue) GetSpec() interface{} {
  type KeyValueSpec (line 26) | type KeyValueSpec struct
  type KeyValueList (line 50) | type KeyValueList struct

FILE: pkg/jetstream/apis/jetstream/v1beta2/objectstoretypes.go
  type ObjectStore (line 11) | type ObjectStore struct
    method GetSpec (line 19) | func (s *ObjectStore) GetSpec() interface{} {
  type ObjectStoreSpec (line 24) | type ObjectStoreSpec struct
  type ObjectStoreList (line 40) | type ObjectStoreList struct

FILE: pkg/jetstream/apis/jetstream/v1beta2/register.go
  function Kind (line 22) | func Kind(kind string) schema.GroupKind {
  function Resource (line 27) | func Resource(resource string) schema.GroupResource {
  function addKnownTypes (line 32) | func addKnownTypes(scheme *runtime.Scheme) error {

FILE: pkg/jetstream/apis/jetstream/v1beta2/streamtypes.go
  type Stream (line 11) | type Stream struct
    method GetSpec (line 19) | func (s *Stream) GetSpec() interface{} {
  type StreamSpec (line 24) | type StreamSpec struct
  type SubjectTransform (line 65) | type SubjectTransform struct
  type StreamPlacement (line 70) | type StreamPlacement struct
  type StreamSource (line 75) | type StreamSource struct
  type RePublish (line 87) | type RePublish struct
  type StreamList (line 96) | type StreamList struct

FILE: pkg/jetstream/apis/jetstream/v1beta2/types.go
  type CredentialsSecret (line 7) | type CredentialsSecret struct
  type Status (line 12) | type Status struct
  type Condition (line 17) | type Condition struct
  type BaseStreamConfig (line 25) | type BaseStreamConfig struct
  type ConnectionOpts (line 31) | type ConnectionOpts struct
  type ConsumerLimits (line 41) | type ConsumerLimits struct
  type TLS (line 46) | type TLS struct
  type TLSSecret (line 52) | type TLSSecret struct
  type CredsSecret (line 59) | type CredsSecret struct
  type NKeySecret (line 64) | type NKeySecret struct
  type TokenSecret (line 69) | type TokenSecret struct
  type User (line 74) | type User struct
  type SecretRef (line 80) | type SecretRef struct

FILE: pkg/jetstream/apis/jetstream/v1beta2/zz_generated.deepcopy.go
  method DeepCopyInto (line 26) | func (in *Account) DeepCopyInto(out *Account) {
  method DeepCopy (line 36) | func (in *Account) DeepCopy() *Account {
  method DeepCopyObject (line 46) | func (in *Account) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 54) | func (in *AccountList) DeepCopyInto(out *AccountList) {
  method DeepCopy (line 69) | func (in *AccountList) DeepCopy() *AccountList {
  method DeepCopyObject (line 79) | func (in *AccountList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 87) | func (in *AccountSpec) DeepCopyInto(out *AccountSpec) {
  method DeepCopy (line 123) | func (in *AccountSpec) DeepCopy() *AccountSpec {
  method DeepCopyInto (line 133) | func (in *BaseStreamConfig) DeepCopyInto(out *BaseStreamConfig) {
  method DeepCopy (line 140) | func (in *BaseStreamConfig) DeepCopy() *BaseStreamConfig {
  method DeepCopyInto (line 150) | func (in *Condition) DeepCopyInto(out *Condition) {
  method DeepCopy (line 156) | func (in *Condition) DeepCopy() *Condition {
  method DeepCopyInto (line 166) | func (in *ConnectionOpts) DeepCopyInto(out *ConnectionOpts) {
  method DeepCopy (line 182) | func (in *ConnectionOpts) DeepCopy() *ConnectionOpts {
  method DeepCopyInto (line 192) | func (in *Consumer) DeepCopyInto(out *Consumer) {
  method DeepCopy (line 202) | func (in *Consumer) DeepCopy() *Consumer {
  method DeepCopyObject (line 212) | func (in *Consumer) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 220) | func (in *ConsumerLimits) DeepCopyInto(out *ConsumerLimits) {
  method DeepCopy (line 226) | func (in *ConsumerLimits) DeepCopy() *ConsumerLimits {
  method DeepCopyInto (line 236) | func (in *ConsumerList) DeepCopyInto(out *ConsumerList) {
  method DeepCopy (line 251) | func (in *ConsumerList) DeepCopy() *ConsumerList {
  method DeepCopyObject (line 261) | func (in *ConsumerList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 269) | func (in *ConsumerSpec) DeepCopyInto(out *ConsumerSpec) {
  method DeepCopy (line 298) | func (in *ConsumerSpec) DeepCopy() *ConsumerSpec {
  method DeepCopyInto (line 308) | func (in *CredentialsSecret) DeepCopyInto(out *CredentialsSecret) {
  method DeepCopy (line 314) | func (in *CredentialsSecret) DeepCopy() *CredentialsSecret {
  method DeepCopyInto (line 324) | func (in *CredsSecret) DeepCopyInto(out *CredsSecret) {
  method DeepCopy (line 335) | func (in *CredsSecret) DeepCopy() *CredsSecret {
  method DeepCopyInto (line 345) | func (in *KeyValue) DeepCopyInto(out *KeyValue) {
  method DeepCopy (line 355) | func (in *KeyValue) DeepCopy() *KeyValue {
  method DeepCopyObject (line 365) | func (in *KeyValue) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 373) | func (in *KeyValueList) DeepCopyInto(out *KeyValueList) {
  method DeepCopy (line 388) | func (in *KeyValueList) DeepCopy() *KeyValueList {
  method DeepCopyObject (line 398) | func (in *KeyValueList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 406) | func (in *KeyValueSpec) DeepCopyInto(out *KeyValueSpec) {
  method DeepCopy (line 439) | func (in *KeyValueSpec) DeepCopy() *KeyValueSpec {
  method DeepCopyInto (line 449) | func (in *NKeySecret) DeepCopyInto(out *NKeySecret) {
  method DeepCopy (line 460) | func (in *NKeySecret) DeepCopy() *NKeySecret {
  method DeepCopyInto (line 470) | func (in *ObjectStore) DeepCopyInto(out *ObjectStore) {
  method DeepCopy (line 480) | func (in *ObjectStore) DeepCopy() *ObjectStore {
  method DeepCopyObject (line 490) | func (in *ObjectStore) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 498) | func (in *ObjectStoreList) DeepCopyInto(out *ObjectStoreList) {
  method DeepCopy (line 513) | func (in *ObjectStoreList) DeepCopy() *ObjectStoreList {
  method DeepCopyObject (line 523) | func (in *ObjectStoreList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 531) | func (in *ObjectStoreSpec) DeepCopyInto(out *ObjectStoreSpec) {
  method DeepCopy (line 550) | func (in *ObjectStoreSpec) DeepCopy() *ObjectStoreSpec {
  method DeepCopyInto (line 560) | func (in *RePublish) DeepCopyInto(out *RePublish) {
  method DeepCopy (line 566) | func (in *RePublish) DeepCopy() *RePublish {
  method DeepCopyInto (line 576) | func (in *SecretRef) DeepCopyInto(out *SecretRef) {
  method DeepCopy (line 582) | func (in *SecretRef) DeepCopy() *SecretRef {
  method DeepCopyInto (line 592) | func (in *Status) DeepCopyInto(out *Status) {
  method DeepCopy (line 603) | func (in *Status) DeepCopy() *Status {
  method DeepCopyInto (line 613) | func (in *Stream) DeepCopyInto(out *Stream) {
  method DeepCopy (line 623) | func (in *Stream) DeepCopy() *Stream {
  method DeepCopyObject (line 633) | func (in *Stream) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 641) | func (in *StreamList) DeepCopyInto(out *StreamList) {
  method DeepCopy (line 656) | func (in *StreamList) DeepCopy() *StreamList {
  method DeepCopyObject (line 666) | func (in *StreamList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 674) | func (in *StreamPlacement) DeepCopyInto(out *StreamPlacement) {
  method DeepCopy (line 685) | func (in *StreamPlacement) DeepCopy() *StreamPlacement {
  method DeepCopyInto (line 695) | func (in *StreamSource) DeepCopyInto(out *StreamSource) {
  method DeepCopy (line 712) | func (in *StreamSource) DeepCopy() *StreamSource {
  method DeepCopyInto (line 722) | func (in *StreamSpec) DeepCopyInto(out *StreamSpec) {
  method DeepCopy (line 777) | func (in *StreamSpec) DeepCopy() *StreamSpec {
  method DeepCopyInto (line 787) | func (in *SubjectTransform) DeepCopyInto(out *SubjectTransform) {
  method DeepCopy (line 793) | func (in *SubjectTransform) DeepCopy() *SubjectTransform {
  method DeepCopyInto (line 803) | func (in *TLS) DeepCopyInto(out *TLS) {
  method DeepCopy (line 814) | func (in *TLS) DeepCopy() *TLS {
  method DeepCopyInto (line 824) | func (in *TLSSecret) DeepCopyInto(out *TLSSecret) {
  method DeepCopy (line 835) | func (in *TLSSecret) DeepCopy() *TLSSecret {
  method DeepCopyInto (line 845) | func (in *TokenSecret) DeepCopyInto(out *TokenSecret) {
  method DeepCopy (line 852) | func (in *TokenSecret) DeepCopy() *TokenSecret {
  method DeepCopyInto (line 862) | func (in *User) DeepCopyInto(out *User) {
  method DeepCopy (line 869) | func (in *User) DeepCopy() *User {

FILE: pkg/jetstream/generated/applyconfiguration/internal/internal.go
  function Parser (line 25) | func Parser() *typed.Parser {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/account.go
  type AccountApplyConfiguration (line 26) | type AccountApplyConfiguration struct
    method IsApplyConfiguration (line 43) | func (b AccountApplyConfiguration) IsApplyConfiguration() {}
    method WithKind (line 48) | func (b *AccountApplyConfiguration) WithKind(value string) *AccountApp...
    method WithAPIVersion (line 56) | func (b *AccountApplyConfiguration) WithAPIVersion(value string) *Acco...
    method WithName (line 64) | func (b *AccountApplyConfiguration) WithName(value string) *AccountApp...
    method WithGenerateName (line 73) | func (b *AccountApplyConfiguration) WithGenerateName(value string) *Ac...
    method WithNamespace (line 82) | func (b *AccountApplyConfiguration) WithNamespace(value string) *Accou...
    method WithUID (line 91) | func (b *AccountApplyConfiguration) WithUID(value types.UID) *AccountA...
    method WithResourceVersion (line 100) | func (b *AccountApplyConfiguration) WithResourceVersion(value string) ...
    method WithGeneration (line 109) | func (b *AccountApplyConfiguration) WithGeneration(value int64) *Accou...
    method WithCreationTimestamp (line 118) | func (b *AccountApplyConfiguration) WithCreationTimestamp(value metav1...
    method WithDeletionTimestamp (line 127) | func (b *AccountApplyConfiguration) WithDeletionTimestamp(value metav1...
    method WithDeletionGracePeriodSeconds (line 136) | func (b *AccountApplyConfiguration) WithDeletionGracePeriodSeconds(val...
    method WithLabels (line 146) | func (b *AccountApplyConfiguration) WithLabels(entries map[string]stri...
    method WithAnnotations (line 161) | func (b *AccountApplyConfiguration) WithAnnotations(entries map[string...
    method WithOwnerReferences (line 175) | func (b *AccountApplyConfiguration) WithOwnerReferences(values ...*v1....
    method WithFinalizers (line 189) | func (b *AccountApplyConfiguration) WithFinalizers(values ...string) *...
    method ensureObjectMetaApplyConfigurationExists (line 197) | func (b *AccountApplyConfiguration) ensureObjectMetaApplyConfiguration...
    method WithSpec (line 206) | func (b *AccountApplyConfiguration) WithSpec(value *AccountSpecApplyCo...
    method WithStatus (line 214) | func (b *AccountApplyConfiguration) WithStatus(value *StatusApplyConfi...
    method GetKind (line 220) | func (b *AccountApplyConfiguration) GetKind() *string {
    method GetAPIVersion (line 225) | func (b *AccountApplyConfiguration) GetAPIVersion() *string {
    method GetName (line 230) | func (b *AccountApplyConfiguration) GetName() *string {
    method GetNamespace (line 236) | func (b *AccountApplyConfiguration) GetNamespace() *string {
  function Account (line 35) | func Account(name, namespace string) *AccountApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/accountspec.go
  type AccountSpecApplyConfiguration (line 20) | type AccountSpecApplyConfiguration struct
    method WithServers (line 38) | func (b *AccountSpecApplyConfiguration) WithServers(values ...string) ...
    method WithTLS (line 48) | func (b *AccountSpecApplyConfiguration) WithTLS(value *TLSSecretApplyC...
    method WithCreds (line 56) | func (b *AccountSpecApplyConfiguration) WithCreds(value *CredsSecretAp...
    method WithNKey (line 64) | func (b *AccountSpecApplyConfiguration) WithNKey(value *NKeySecretAppl...
    method WithToken (line 72) | func (b *AccountSpecApplyConfiguration) WithToken(value *TokenSecretAp...
    method WithUser (line 80) | func (b *AccountSpecApplyConfiguration) WithUser(value *UserApplyConfi...
  function AccountSpec (line 31) | func AccountSpec() *AccountSpecApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/basestreamconfig.go
  type BaseStreamConfigApplyConfiguration (line 20) | type BaseStreamConfigApplyConfiguration struct
    method WithPreventDelete (line 34) | func (b *BaseStreamConfigApplyConfiguration) WithPreventDelete(value b...
    method WithPreventUpdate (line 42) | func (b *BaseStreamConfigApplyConfiguration) WithPreventUpdate(value b...
  function BaseStreamConfig (line 27) | func BaseStreamConfig() *BaseStreamConfigApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/condition.go
  type ConditionApplyConfiguration (line 24) | type ConditionApplyConfiguration struct
    method WithType (line 41) | func (b *ConditionApplyConfiguration) WithType(value string) *Conditio...
    method WithStatus (line 49) | func (b *ConditionApplyConfiguration) WithStatus(value v1.ConditionSta...
    method WithReason (line 57) | func (b *ConditionApplyConfiguration) WithReason(value string) *Condit...
    method WithMessage (line 65) | func (b *ConditionApplyConfiguration) WithMessage(value string) *Condi...
    method WithLastTransitionTime (line 73) | func (b *ConditionApplyConfiguration) WithLastTransitionTime(value str...
  function Condition (line 34) | func Condition() *ConditionApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/connectionopts.go
  type ConnectionOptsApplyConfiguration (line 20) | type ConnectionOptsApplyConfiguration struct
    method WithAccount (line 39) | func (b *ConnectionOptsApplyConfiguration) WithAccount(value string) *...
    method WithCreds (line 47) | func (b *ConnectionOptsApplyConfiguration) WithCreds(value string) *Co...
    method WithNkey (line 55) | func (b *ConnectionOptsApplyConfiguration) WithNkey(value string) *Con...
    method WithServers (line 63) | func (b *ConnectionOptsApplyConfiguration) WithServers(values ...strin...
    method WithTLS (line 73) | func (b *ConnectionOptsApplyConfiguration) WithTLS(value *TLSApplyConf...
    method WithTLSFirst (line 81) | func (b *ConnectionOptsApplyConfiguration) WithTLSFirst(value bool) *C...
    method WithJsDomain (line 89) | func (b *ConnectionOptsApplyConfiguration) WithJsDomain(value string) ...
  function ConnectionOpts (line 32) | func ConnectionOpts() *ConnectionOptsApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/consumer.go
  type ConsumerApplyConfiguration (line 26) | type ConsumerApplyConfiguration struct
    method IsApplyConfiguration (line 43) | func (b ConsumerApplyConfiguration) IsApplyConfiguration() {}
    method WithKind (line 48) | func (b *ConsumerApplyConfiguration) WithKind(value string) *ConsumerA...
    method WithAPIVersion (line 56) | func (b *ConsumerApplyConfiguration) WithAPIVersion(value string) *Con...
    method WithName (line 64) | func (b *ConsumerApplyConfiguration) WithName(value string) *ConsumerA...
    method WithGenerateName (line 73) | func (b *ConsumerApplyConfiguration) WithGenerateName(value string) *C...
    method WithNamespace (line 82) | func (b *ConsumerApplyConfiguration) WithNamespace(value string) *Cons...
    method WithUID (line 91) | func (b *ConsumerApplyConfiguration) WithUID(value types.UID) *Consume...
    method WithResourceVersion (line 100) | func (b *ConsumerApplyConfiguration) WithResourceVersion(value string)...
    method WithGeneration (line 109) | func (b *ConsumerApplyConfiguration) WithGeneration(value int64) *Cons...
    method WithCreationTimestamp (line 118) | func (b *ConsumerApplyConfiguration) WithCreationTimestamp(value metav...
    method WithDeletionTimestamp (line 127) | func (b *ConsumerApplyConfiguration) WithDeletionTimestamp(value metav...
    method WithDeletionGracePeriodSeconds (line 136) | func (b *ConsumerApplyConfiguration) WithDeletionGracePeriodSeconds(va...
    method WithLabels (line 146) | func (b *ConsumerApplyConfiguration) WithLabels(entries map[string]str...
    method WithAnnotations (line 161) | func (b *ConsumerApplyConfiguration) WithAnnotations(entries map[strin...
    method WithOwnerReferences (line 175) | func (b *ConsumerApplyConfiguration) WithOwnerReferences(values ...*v1...
    method WithFinalizers (line 189) | func (b *ConsumerApplyConfiguration) WithFinalizers(values ...string) ...
    method ensureObjectMetaApplyConfigurationExists (line 197) | func (b *ConsumerApplyConfiguration) ensureObjectMetaApplyConfiguratio...
    method WithSpec (line 206) | func (b *ConsumerApplyConfiguration) WithSpec(value *ConsumerSpecApply...
    method WithStatus (line 214) | func (b *ConsumerApplyConfiguration) WithStatus(value *StatusApplyConf...
    method GetKind (line 220) | func (b *ConsumerApplyConfiguration) GetKind() *string {
    method GetAPIVersion (line 225) | func (b *ConsumerApplyConfiguration) GetAPIVersion() *string {
    method GetName (line 230) | func (b *ConsumerApplyConfiguration) GetName() *string {
    method GetNamespace (line 236) | func (b *ConsumerApplyConfiguration) GetNamespace() *string {
  function Consumer (line 35) | func Consumer(name, namespace string) *ConsumerApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/consumerlimits.go
  type ConsumerLimitsApplyConfiguration (line 20) | type ConsumerLimitsApplyConfiguration struct
    method WithInactiveThreshold (line 34) | func (b *ConsumerLimitsApplyConfiguration) WithInactiveThreshold(value...
    method WithMaxAckPending (line 42) | func (b *ConsumerLimitsApplyConfiguration) WithMaxAckPending(value int...
  function ConsumerLimits (line 27) | func ConsumerLimits() *ConsumerLimitsApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/consumerspec.go
  type ConsumerSpecApplyConfiguration (line 20) | type ConsumerSpecApplyConfiguration struct
    method WithDescription (line 65) | func (b *ConsumerSpecApplyConfiguration) WithDescription(value string)...
    method WithAckPolicy (line 73) | func (b *ConsumerSpecApplyConfiguration) WithAckPolicy(value string) *...
    method WithAckWait (line 81) | func (b *ConsumerSpecApplyConfiguration) WithAckWait(value string) *Co...
    method WithDeliverPolicy (line 89) | func (b *ConsumerSpecApplyConfiguration) WithDeliverPolicy(value strin...
    method WithDeliverSubject (line 97) | func (b *ConsumerSpecApplyConfiguration) WithDeliverSubject(value stri...
    method WithDeliverGroup (line 105) | func (b *ConsumerSpecApplyConfiguration) WithDeliverGroup(value string...
    method WithDurableName (line 113) | func (b *ConsumerSpecApplyConfiguration) WithDurableName(value string)...
    method WithFilterSubject (line 121) | func (b *ConsumerSpecApplyConfiguration) WithFilterSubject(value strin...
    method WithFilterSubjects (line 129) | func (b *ConsumerSpecApplyConfiguration) WithFilterSubjects(values ......
    method WithFlowControl (line 139) | func (b *ConsumerSpecApplyConfiguration) WithFlowControl(value bool) *...
    method WithHeartbeatInterval (line 147) | func (b *ConsumerSpecApplyConfiguration) WithHeartbeatInterval(value s...
    method WithMaxAckPending (line 155) | func (b *ConsumerSpecApplyConfiguration) WithMaxAckPending(value int) ...
    method WithMaxDeliver (line 163) | func (b *ConsumerSpecApplyConfiguration) WithMaxDeliver(value int) *Co...
    method WithBackOff (line 171) | func (b *ConsumerSpecApplyConfiguration) WithBackOff(values ...string)...
    method WithMaxWaiting (line 181) | func (b *ConsumerSpecApplyConfiguration) WithMaxWaiting(value int) *Co...
    method WithOptStartSeq (line 189) | func (b *ConsumerSpecApplyConfiguration) WithOptStartSeq(value int) *C...
    method WithOptStartTime (line 197) | func (b *ConsumerSpecApplyConfiguration) WithOptStartTime(value string...
    method WithRateLimitBps (line 205) | func (b *ConsumerSpecApplyConfiguration) WithRateLimitBps(value int) *...
    method WithReplayPolicy (line 213) | func (b *ConsumerSpecApplyConfiguration) WithReplayPolicy(value string...
    method WithSampleFreq (line 221) | func (b *ConsumerSpecApplyConfiguration) WithSampleFreq(value string) ...
    method WithHeadersOnly (line 229) | func (b *ConsumerSpecApplyConfiguration) WithHeadersOnly(value bool) *...
    method WithMaxRequestBatch (line 237) | func (b *ConsumerSpecApplyConfiguration) WithMaxRequestBatch(value int...
    method WithMaxRequestExpires (line 245) | func (b *ConsumerSpecApplyConfiguration) WithMaxRequestExpires(value s...
    method WithMaxRequestMaxBytes (line 253) | func (b *ConsumerSpecApplyConfiguration) WithMaxRequestMaxBytes(value ...
    method WithInactiveThreshold (line 261) | func (b *ConsumerSpecApplyConfiguration) WithInactiveThreshold(value s...
    method WithReplicas (line 269) | func (b *ConsumerSpecApplyConfiguration) WithReplicas(value int) *Cons...
    method WithMemStorage (line 277) | func (b *ConsumerSpecApplyConfiguration) WithMemStorage(value bool) *C...
    method WithMetadata (line 286) | func (b *ConsumerSpecApplyConfiguration) WithMetadata(entries map[stri...
    method WithPauseUntil (line 299) | func (b *ConsumerSpecApplyConfiguration) WithPauseUntil(value string) ...
    method WithPriorityPolicy (line 307) | func (b *ConsumerSpecApplyConfiguration) WithPriorityPolicy(value stri...
    method WithPinnedTTL (line 315) | func (b *ConsumerSpecApplyConfiguration) WithPinnedTTL(value string) *...
    method WithPriorityGroups (line 323) | func (b *ConsumerSpecApplyConfiguration) WithPriorityGroups(values ......
    method WithStreamName (line 333) | func (b *ConsumerSpecApplyConfiguration) WithStreamName(value string) ...
  function ConsumerSpec (line 58) | func ConsumerSpec() *ConsumerSpecApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/credssecret.go
  type CredsSecretApplyConfiguration (line 20) | type CredsSecretApplyConfiguration struct
    method WithFile (line 34) | func (b *CredsSecretApplyConfiguration) WithFile(value string) *CredsS...
    method WithSecret (line 42) | func (b *CredsSecretApplyConfiguration) WithSecret(value *SecretRefApp...
  function CredsSecret (line 27) | func CredsSecret() *CredsSecretApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/keyvalue.go
  type KeyValueApplyConfiguration (line 26) | type KeyValueApplyConfiguration struct
    method IsApplyConfiguration (line 43) | func (b KeyValueApplyConfiguration) IsApplyConfiguration() {}
    method WithKind (line 48) | func (b *KeyValueApplyConfiguration) WithKind(value string) *KeyValueA...
    method WithAPIVersion (line 56) | func (b *KeyValueApplyConfiguration) WithAPIVersion(value string) *Key...
    method WithName (line 64) | func (b *KeyValueApplyConfiguration) WithName(value string) *KeyValueA...
    method WithGenerateName (line 73) | func (b *KeyValueApplyConfiguration) WithGenerateName(value string) *K...
    method WithNamespace (line 82) | func (b *KeyValueApplyConfiguration) WithNamespace(value string) *KeyV...
    method WithUID (line 91) | func (b *KeyValueApplyConfiguration) WithUID(value types.UID) *KeyValu...
    method WithResourceVersion (line 100) | func (b *KeyValueApplyConfiguration) WithResourceVersion(value string)...
    method WithGeneration (line 109) | func (b *KeyValueApplyConfiguration) WithGeneration(value int64) *KeyV...
    method WithCreationTimestamp (line 118) | func (b *KeyValueApplyConfiguration) WithCreationTimestamp(value metav...
    method WithDeletionTimestamp (line 127) | func (b *KeyValueApplyConfiguration) WithDeletionTimestamp(value metav...
    method WithDeletionGracePeriodSeconds (line 136) | func (b *KeyValueApplyConfiguration) WithDeletionGracePeriodSeconds(va...
    method WithLabels (line 146) | func (b *KeyValueApplyConfiguration) WithLabels(entries map[string]str...
    method WithAnnotations (line 161) | func (b *KeyValueApplyConfiguration) WithAnnotations(entries map[strin...
    method WithOwnerReferences (line 175) | func (b *KeyValueApplyConfiguration) WithOwnerReferences(values ...*v1...
    method WithFinalizers (line 189) | func (b *KeyValueApplyConfiguration) WithFinalizers(values ...string) ...
    method ensureObjectMetaApplyConfigurationExists (line 197) | func (b *KeyValueApplyConfiguration) ensureObjectMetaApplyConfiguratio...
    method WithSpec (line 206) | func (b *KeyValueApplyConfiguration) WithSpec(value *KeyValueSpecApply...
    method WithStatus (line 214) | func (b *KeyValueApplyConfiguration) WithStatus(value *StatusApplyConf...
    method GetKind (line 220) | func (b *KeyValueApplyConfiguration) GetKind() *string {
    method GetAPIVersion (line 225) | func (b *KeyValueApplyConfiguration) GetAPIVersion() *string {
    method GetName (line 230) | func (b *KeyValueApplyConfiguration) GetName() *string {
    method GetNamespace (line 236) | func (b *KeyValueApplyConfiguration) GetNamespace() *string {
  function KeyValue (line 35) | func KeyValue(name, namespace string) *KeyValueApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/keyvaluespec.go
  type KeyValueSpecApplyConfiguration (line 26) | type KeyValueSpecApplyConfiguration struct
    method WithBucket (line 52) | func (b *KeyValueSpecApplyConfiguration) WithBucket(value string) *Key...
    method WithDescription (line 60) | func (b *KeyValueSpecApplyConfiguration) WithDescription(value string)...
    method WithMaxValueSize (line 68) | func (b *KeyValueSpecApplyConfiguration) WithMaxValueSize(value int) *...
    method WithHistory (line 76) | func (b *KeyValueSpecApplyConfiguration) WithHistory(value int) *KeyVa...
    method WithTTL (line 84) | func (b *KeyValueSpecApplyConfiguration) WithTTL(value string) *KeyVal...
    method WithMaxBytes (line 92) | func (b *KeyValueSpecApplyConfiguration) WithMaxBytes(value int) *KeyV...
    method WithStorage (line 100) | func (b *KeyValueSpecApplyConfiguration) WithStorage(value string) *Ke...
    method WithReplicas (line 108) | func (b *KeyValueSpecApplyConfiguration) WithReplicas(value int) *KeyV...
    method WithPlacement (line 116) | func (b *KeyValueSpecApplyConfiguration) WithPlacement(value *StreamPl...
    method WithRePublish (line 124) | func (b *KeyValueSpecApplyConfiguration) WithRePublish(value *RePublis...
    method WithMirror (line 132) | func (b *KeyValueSpecApplyConfiguration) WithMirror(value *StreamSourc...
    method WithSources (line 140) | func (b *KeyValueSpecApplyConfiguration) WithSources(values ...**jetst...
    method WithCompression (line 153) | func (b *KeyValueSpecApplyConfiguration) WithCompression(value bool) *...
    method WithLimitMarkerTTL (line 161) | func (b *KeyValueSpecApplyConfiguration) WithLimitMarkerTTL(value time...
  function KeyValueSpec (line 45) | func KeyValueSpec() *KeyValueSpecApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/nkeysecret.go
  type NKeySecretApplyConfiguration (line 20) | type NKeySecretApplyConfiguration struct
    method WithSeed (line 34) | func (b *NKeySecretApplyConfiguration) WithSeed(value string) *NKeySec...
    method WithSecret (line 42) | func (b *NKeySecretApplyConfiguration) WithSecret(value *SecretRefAppl...
  function NKeySecret (line 27) | func NKeySecret() *NKeySecretApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/objectstore.go
  type ObjectStoreApplyConfiguration (line 26) | type ObjectStoreApplyConfiguration struct
    method IsApplyConfiguration (line 43) | func (b ObjectStoreApplyConfiguration) IsApplyConfiguration() {}
    method WithKind (line 48) | func (b *ObjectStoreApplyConfiguration) WithKind(value string) *Object...
    method WithAPIVersion (line 56) | func (b *ObjectStoreApplyConfiguration) WithAPIVersion(value string) *...
    method WithName (line 64) | func (b *ObjectStoreApplyConfiguration) WithName(value string) *Object...
    method WithGenerateName (line 73) | func (b *ObjectStoreApplyConfiguration) WithGenerateName(value string)...
    method WithNamespace (line 82) | func (b *ObjectStoreApplyConfiguration) WithNamespace(value string) *O...
    method WithUID (line 91) | func (b *ObjectStoreApplyConfiguration) WithUID(value types.UID) *Obje...
    method WithResourceVersion (line 100) | func (b *ObjectStoreApplyConfiguration) WithResourceVersion(value stri...
    method WithGeneration (line 109) | func (b *ObjectStoreApplyConfiguration) WithGeneration(value int64) *O...
    method WithCreationTimestamp (line 118) | func (b *ObjectStoreApplyConfiguration) WithCreationTimestamp(value me...
    method WithDeletionTimestamp (line 127) | func (b *ObjectStoreApplyConfiguration) WithDeletionTimestamp(value me...
    method WithDeletionGracePeriodSeconds (line 136) | func (b *ObjectStoreApplyConfiguration) WithDeletionGracePeriodSeconds...
    method WithLabels (line 146) | func (b *ObjectStoreApplyConfiguration) WithLabels(entries map[string]...
    method WithAnnotations (line 161) | func (b *ObjectStoreApplyConfiguration) WithAnnotations(entries map[st...
    method WithOwnerReferences (line 175) | func (b *ObjectStoreApplyConfiguration) WithOwnerReferences(values ......
    method WithFinalizers (line 189) | func (b *ObjectStoreApplyConfiguration) WithFinalizers(values ...strin...
    method ensureObjectMetaApplyConfigurationExists (line 197) | func (b *ObjectStoreApplyConfiguration) ensureObjectMetaApplyConfigura...
    method WithSpec (line 206) | func (b *ObjectStoreApplyConfiguration) WithSpec(value *ObjectStoreSpe...
    method WithStatus (line 214) | func (b *ObjectStoreApplyConfiguration) WithStatus(value *StatusApplyC...
    method GetKind (line 220) | func (b *ObjectStoreApplyConfiguration) GetKind() *string {
    method GetAPIVersion (line 225) | func (b *ObjectStoreApplyConfiguration) GetAPIVersion() *string {
    method GetName (line 230) | func (b *ObjectStoreApplyConfiguration) GetName() *string {
    method GetNamespace (line 236) | func (b *ObjectStoreApplyConfiguration) GetNamespace() *string {
  function ObjectStore (line 35) | func ObjectStore(name, namespace string) *ObjectStoreApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/objectstorespec.go
  type ObjectStoreSpecApplyConfiguration (line 20) | type ObjectStoreSpecApplyConfiguration struct
    method WithBucket (line 41) | func (b *ObjectStoreSpecApplyConfiguration) WithBucket(value string) *...
    method WithDescription (line 49) | func (b *ObjectStoreSpecApplyConfiguration) WithDescription(value stri...
    method WithTTL (line 57) | func (b *ObjectStoreSpecApplyConfiguration) WithTTL(value string) *Obj...
    method WithMaxBytes (line 65) | func (b *ObjectStoreSpecApplyConfiguration) WithMaxBytes(value int) *O...
    method WithStorage (line 73) | func (b *ObjectStoreSpecApplyConfiguration) WithStorage(value string) ...
    method WithReplicas (line 81) | func (b *ObjectStoreSpecApplyConfiguration) WithReplicas(value int) *O...
    method WithPlacement (line 89) | func (b *ObjectStoreSpecApplyConfiguration) WithPlacement(value *Strea...
    method WithCompression (line 97) | func (b *ObjectStoreSpecApplyConfiguration) WithCompression(value bool...
    method WithMetadata (line 106) | func (b *ObjectStoreSpecApplyConfiguration) WithMetadata(entries map[s...
  function ObjectStoreSpec (line 34) | func ObjectStoreSpec() *ObjectStoreSpecApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/republish.go
  type RePublishApplyConfiguration (line 20) | type RePublishApplyConfiguration struct
    method WithSource (line 35) | func (b *RePublishApplyConfiguration) WithSource(value string) *RePubl...
    method WithDestination (line 43) | func (b *RePublishApplyConfiguration) WithDestination(value string) *R...
    method WithHeadersOnly (line 51) | func (b *RePublishApplyConfiguration) WithHeadersOnly(value bool) *ReP...
  function RePublish (line 28) | func RePublish() *RePublishApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/secretref.go
  type SecretRefApplyConfiguration (line 20) | type SecretRefApplyConfiguration struct
    method WithName (line 33) | func (b *SecretRefApplyConfiguration) WithName(value string) *SecretRe...
  function SecretRef (line 26) | func SecretRef() *SecretRefApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/status.go
  type StatusApplyConfiguration (line 20) | type StatusApplyConfiguration struct
    method WithObservedGeneration (line 34) | func (b *StatusApplyConfiguration) WithObservedGeneration(value int64)...
    method WithConditions (line 42) | func (b *StatusApplyConfiguration) WithConditions(values ...*Condition...
  function Status (line 27) | func Status() *StatusApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/stream.go
  type StreamApplyConfiguration (line 26) | type StreamApplyConfiguration struct
    method IsApplyConfiguration (line 43) | func (b StreamApplyConfiguration) IsApplyConfiguration() {}
    method WithKind (line 48) | func (b *StreamApplyConfiguration) WithKind(value string) *StreamApply...
    method WithAPIVersion (line 56) | func (b *StreamApplyConfiguration) WithAPIVersion(value string) *Strea...
    method WithName (line 64) | func (b *StreamApplyConfiguration) WithName(value string) *StreamApply...
    method WithGenerateName (line 73) | func (b *StreamApplyConfiguration) WithGenerateName(value string) *Str...
    method WithNamespace (line 82) | func (b *StreamApplyConfiguration) WithNamespace(value string) *Stream...
    method WithUID (line 91) | func (b *StreamApplyConfiguration) WithUID(value types.UID) *StreamApp...
    method WithResourceVersion (line 100) | func (b *StreamApplyConfiguration) WithResourceVersion(value string) *...
    method WithGeneration (line 109) | func (b *StreamApplyConfiguration) WithGeneration(value int64) *Stream...
    method WithCreationTimestamp (line 118) | func (b *StreamApplyConfiguration) WithCreationTimestamp(value metav1....
    method WithDeletionTimestamp (line 127) | func (b *StreamApplyConfiguration) WithDeletionTimestamp(value metav1....
    method WithDeletionGracePeriodSeconds (line 136) | func (b *StreamApplyConfiguration) WithDeletionGracePeriodSeconds(valu...
    method WithLabels (line 146) | func (b *StreamApplyConfiguration) WithLabels(entries map[string]strin...
    method WithAnnotations (line 161) | func (b *StreamApplyConfiguration) WithAnnotations(entries map[string]...
    method WithOwnerReferences (line 175) | func (b *StreamApplyConfiguration) WithOwnerReferences(values ...*v1.O...
    method WithFinalizers (line 189) | func (b *StreamApplyConfiguration) WithFinalizers(values ...string) *S...
    method ensureObjectMetaApplyConfigurationExists (line 197) | func (b *StreamApplyConfiguration) ensureObjectMetaApplyConfigurationE...
    method WithSpec (line 206) | func (b *StreamApplyConfiguration) WithSpec(value *StreamSpecApplyConf...
    method WithStatus (line 214) | func (b *StreamApplyConfiguration) WithStatus(value *StatusApplyConfig...
    method GetKind (line 220) | func (b *StreamApplyConfiguration) GetKind() *string {
    method GetAPIVersion (line 225) | func (b *StreamApplyConfiguration) GetAPIVersion() *string {
    method GetName (line 230) | func (b *StreamApplyConfiguration) GetName() *string {
    method GetNamespace (line 236) | func (b *StreamApplyConfiguration) GetNamespace() *string {
  function Stream (line 35) | func Stream(name, namespace string) *StreamApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/streamplacement.go
  type StreamPlacementApplyConfiguration (line 20) | type StreamPlacementApplyConfiguration struct
    method WithCluster (line 34) | func (b *StreamPlacementApplyConfiguration) WithCluster(value string) ...
    method WithTags (line 42) | func (b *StreamPlacementApplyConfiguration) WithTags(values ...string)...
  function StreamPlacement (line 27) | func StreamPlacement() *StreamPlacementApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/streamsource.go
  type StreamSourceApplyConfiguration (line 24) | type StreamSourceApplyConfiguration struct
    method WithName (line 43) | func (b *StreamSourceApplyConfiguration) WithName(value string) *Strea...
    method WithOptStartSeq (line 51) | func (b *StreamSourceApplyConfiguration) WithOptStartSeq(value int) *S...
    method WithOptStartTime (line 59) | func (b *StreamSourceApplyConfiguration) WithOptStartTime(value string...
    method WithFilterSubject (line 67) | func (b *StreamSourceApplyConfiguration) WithFilterSubject(value strin...
    method WithExternalAPIPrefix (line 75) | func (b *StreamSourceApplyConfiguration) WithExternalAPIPrefix(value s...
    method WithExternalDeliverPrefix (line 83) | func (b *StreamSourceApplyConfiguration) WithExternalDeliverPrefix(val...
    method WithSubjectTransforms (line 91) | func (b *StreamSourceApplyConfiguration) WithSubjectTransforms(values ...
  function StreamSource (line 36) | func StreamSource() *StreamSourceApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/streamspec.go
  type StreamSpecApplyConfiguration (line 24) | type StreamSpecApplyConfiguration struct
    method WithName (line 73) | func (b *StreamSpecApplyConfiguration) WithName(value string) *StreamS...
    method WithDescription (line 81) | func (b *StreamSpecApplyConfiguration) WithDescription(value string) *...
    method WithSubjects (line 89) | func (b *StreamSpecApplyConfiguration) WithSubjects(values ...string) ...
    method WithRetention (line 99) | func (b *StreamSpecApplyConfiguration) WithRetention(value string) *St...
    method WithMaxConsumers (line 107) | func (b *StreamSpecApplyConfiguration) WithMaxConsumers(value int) *St...
    method WithMaxMsgsPerSubject (line 115) | func (b *StreamSpecApplyConfiguration) WithMaxMsgsPerSubject(value int...
    method WithMaxMsgs (line 123) | func (b *StreamSpecApplyConfiguration) WithMaxMsgs(value int) *StreamS...
    method WithMaxBytes (line 131) | func (b *StreamSpecApplyConfiguration) WithMaxBytes(value int) *Stream...
    method WithMaxAge (line 139) | func (b *StreamSpecApplyConfiguration) WithMaxAge(value string) *Strea...
    method WithMaxMsgSize (line 147) | func (b *StreamSpecApplyConfiguration) WithMaxMsgSize(value int) *Stre...
    method WithStorage (line 155) | func (b *StreamSpecApplyConfiguration) WithStorage(value string) *Stre...
    method WithDiscard (line 163) | func (b *StreamSpecApplyConfiguration) WithDiscard(value string) *Stre...
    method WithReplicas (line 171) | func (b *StreamSpecApplyConfiguration) WithReplicas(value int) *Stream...
    method WithNoAck (line 179) | func (b *StreamSpecApplyConfiguration) WithNoAck(value bool) *StreamSp...
    method WithDuplicateWindow (line 187) | func (b *StreamSpecApplyConfiguration) WithDuplicateWindow(value strin...
    method WithPlacement (line 195) | func (b *StreamSpecApplyConfiguration) WithPlacement(value *StreamPlac...
    method WithMirror (line 203) | func (b *StreamSpecApplyConfiguration) WithMirror(value *StreamSourceA...
    method WithSources (line 211) | func (b *StreamSpecApplyConfiguration) WithSources(values ...**jetstre...
    method WithCompression (line 224) | func (b *StreamSpecApplyConfiguration) WithCompression(value string) *...
    method WithSubjectTransform (line 232) | func (b *StreamSpecApplyConfiguration) WithSubjectTransform(value *Sub...
    method WithRePublish (line 240) | func (b *StreamSpecApplyConfiguration) WithRePublish(value *RePublishA...
    method WithSealed (line 248) | func (b *StreamSpecApplyConfiguration) WithSealed(value bool) *StreamS...
    method WithDenyDelete (line 256) | func (b *StreamSpecApplyConfiguration) WithDenyDelete(value bool) *Str...
    method WithDenyPurge (line 264) | func (b *StreamSpecApplyConfiguration) WithDenyPurge(value bool) *Stre...
    method WithAllowDirect (line 272) | func (b *StreamSpecApplyConfiguration) WithAllowDirect(value bool) *St...
    method WithAllowRollup (line 280) | func (b *StreamSpecApplyConfiguration) WithAllowRollup(value bool) *St...
    method WithMirrorDirect (line 288) | func (b *StreamSpecApplyConfiguration) WithMirrorDirect(value bool) *S...
    method WithDiscardPerSubject (line 296) | func (b *StreamSpecApplyConfiguration) WithDiscardPerSubject(value boo...
    method WithFirstSequence (line 304) | func (b *StreamSpecApplyConfiguration) WithFirstSequence(value uint64)...
    method WithMetadata (line 313) | func (b *StreamSpecApplyConfiguration) WithMetadata(entries map[string...
    method WithConsumerLimits (line 326) | func (b *StreamSpecApplyConfiguration) WithConsumerLimits(value *Consu...
    method WithAllowMsgTTL (line 334) | func (b *StreamSpecApplyConfiguration) WithAllowMsgTTL(value bool) *St...
    method WithSubjectDeleteMarkerTTL (line 342) | func (b *StreamSpecApplyConfiguration) WithSubjectDeleteMarkerTTL(valu...
    method WithAllowMsgCounter (line 350) | func (b *StreamSpecApplyConfiguration) WithAllowMsgCounter(value bool)...
    method WithAllowAtomicPublish (line 358) | func (b *StreamSpecApplyConfiguration) WithAllowAtomicPublish(value bo...
    method WithAllowMsgSchedules (line 366) | func (b *StreamSpecApplyConfiguration) WithAllowMsgSchedules(value boo...
    method WithPersistMode (line 374) | func (b *StreamSpecApplyConfiguration) WithPersistMode(value string) *...
  function StreamSpec (line 66) | func StreamSpec() *StreamSpecApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/subjecttransform.go
  type SubjectTransformApplyConfiguration (line 20) | type SubjectTransformApplyConfiguration struct
    method WithSource (line 34) | func (b *SubjectTransformApplyConfiguration) WithSource(value string) ...
    method WithDest (line 42) | func (b *SubjectTransformApplyConfiguration) WithDest(value string) *S...
  function SubjectTransform (line 27) | func SubjectTransform() *SubjectTransformApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/tls.go
  type TLSApplyConfiguration (line 20) | type TLSApplyConfiguration struct
    method WithClientCert (line 35) | func (b *TLSApplyConfiguration) WithClientCert(value string) *TLSApply...
    method WithClientKey (line 43) | func (b *TLSApplyConfiguration) WithClientKey(value string) *TLSApplyC...
    method WithRootCAs (line 51) | func (b *TLSApplyConfiguration) WithRootCAs(values ...string) *TLSAppl...
  function TLS (line 28) | func TLS() *TLSApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/tlssecret.go
  type TLSSecretApplyConfiguration (line 20) | type TLSSecretApplyConfiguration struct
    method WithClientCert (line 36) | func (b *TLSSecretApplyConfiguration) WithClientCert(value string) *TL...
    method WithClientKey (line 44) | func (b *TLSSecretApplyConfiguration) WithClientKey(value string) *TLS...
    method WithRootCAs (line 52) | func (b *TLSSecretApplyConfiguration) WithRootCAs(value string) *TLSSe...
    method WithSecret (line 60) | func (b *TLSSecretApplyConfiguration) WithSecret(value *SecretRefApply...
  function TLSSecret (line 29) | func TLSSecret() *TLSSecretApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/tokensecret.go
  type TokenSecretApplyConfiguration (line 20) | type TokenSecretApplyConfiguration struct
    method WithToken (line 34) | func (b *TokenSecretApplyConfiguration) WithToken(value string) *Token...
    method WithSecret (line 42) | func (b *TokenSecretApplyConfiguration) WithSecret(value *SecretRefApp...
  function TokenSecret (line 27) | func TokenSecret() *TokenSecretApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/user.go
  type UserApplyConfiguration (line 20) | type UserApplyConfiguration struct
    method WithUser (line 35) | func (b *UserApplyConfiguration) WithUser(value string) *UserApplyConf...
    method WithPassword (line 43) | func (b *UserApplyConfiguration) WithPassword(value string) *UserApply...
    method WithSecret (line 51) | func (b *UserApplyConfiguration) WithSecret(value *SecretRefApplyConfi...
  function User (line 28) | func User() *UserApplyConfiguration {

FILE: pkg/jetstream/generated/applyconfiguration/utils.go
  function ForKind (line 29) | func ForKind(kind schema.GroupVersionKind) interface{} {
  function NewTypeConverter (line 89) | func NewTypeConverter(scheme *runtime.Scheme) managedfields.TypeConverter {

FILE: pkg/jetstream/generated/clientset/versioned/clientset.go
  type Interface (line 28) | type Interface interface
  type Clientset (line 34) | type Clientset struct
    method JetstreamV1beta2 (line 40) | func (c *Clientset) JetstreamV1beta2() jetstreamv1beta2.JetstreamV1bet...
    method Discovery (line 45) | func (c *Clientset) Discovery() discovery.DiscoveryInterface {
  function NewForConfig (line 57) | func NewForConfig(c *rest.Config) (*Clientset, error) {
  function NewForConfigAndClient (line 77) | func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Cl...
  function NewForConfigOrDie (line 102) | func NewForConfigOrDie(c *rest.Config) *Clientset {
  function New (line 111) | func New(c rest.Interface) *Clientset {

FILE: pkg/jetstream/generated/clientset/versioned/fake/clientset_generated.go
  function NewSimpleClientset (line 39) | func NewSimpleClientset(objects ...runtime.Object) *Clientset {
  type Clientset (line 70) | type Clientset struct
    method Discovery (line 76) | func (c *Clientset) Discovery() discovery.DiscoveryInterface {
    method Tracker (line 80) | func (c *Clientset) Tracker() testing.ObjectTracker {
    method JetstreamV1beta2 (line 126) | func (c *Clientset) JetstreamV1beta2() jetstreamv1beta2.JetstreamV1bet...
  function NewClientset (line 88) | func NewClientset(objects ...runtime.Object) *Clientset {

FILE: pkg/jetstream/generated/clientset/versioned/fake/register.go
  function init (line 50) | func init() {

FILE: pkg/jetstream/generated/clientset/versioned/scheme/register.go
  function init (line 50) | func init() {

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/account.go
  type AccountsGetter (line 32) | type AccountsGetter interface
  type AccountInterface (line 37) | type AccountInterface interface
  type accounts (line 55) | type accounts struct
  function newAccounts (line 60) | func newAccounts(c *JetstreamV1beta2Client, namespace string) *accounts {

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/consumer.go
  type ConsumersGetter (line 32) | type ConsumersGetter interface
  type ConsumerInterface (line 37) | type ConsumerInterface interface
  type consumers (line 55) | type consumers struct
  function newConsumers (line 60) | func newConsumers(c *JetstreamV1beta2Client, namespace string) *consumers {

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_account.go
  type fakeAccounts (line 26) | type fakeAccounts struct
  function newFakeAccounts (line 31) | func newFakeAccounts(fake *FakeJetstreamV1beta2, namespace string) typed...

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_consumer.go
  type fakeConsumers (line 26) | type fakeConsumers struct
  function newFakeConsumers (line 31) | func newFakeConsumers(fake *FakeJetstreamV1beta2, namespace string) type...

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_jetstream_client.go
  type FakeJetstreamV1beta2 (line 24) | type FakeJetstreamV1beta2 struct
    method Accounts (line 28) | func (c *FakeJetstreamV1beta2) Accounts(namespace string) v1beta2.Acco...
    method Consumers (line 32) | func (c *FakeJetstreamV1beta2) Consumers(namespace string) v1beta2.Con...
    method KeyValues (line 36) | func (c *FakeJetstreamV1beta2) KeyValues(namespace string) v1beta2.Key...
    method ObjectStores (line 40) | func (c *FakeJetstreamV1beta2) ObjectStores(namespace string) v1beta2....
    method Streams (line 44) | func (c *FakeJetstreamV1beta2) Streams(namespace string) v1beta2.Strea...
    method RESTClient (line 50) | func (c *FakeJetstreamV1beta2) RESTClient() rest.Interface {

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_keyvalue.go
  type fakeKeyValues (line 26) | type fakeKeyValues struct
  function newFakeKeyValues (line 31) | func newFakeKeyValues(fake *FakeJetstreamV1beta2, namespace string) type...

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_objectstore.go
  type fakeObjectStores (line 26) | type fakeObjectStores struct
  function newFakeObjectStores (line 31) | func newFakeObjectStores(fake *FakeJetstreamV1beta2, namespace string) t...

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_stream.go
  type fakeStreams (line 26) | type fakeStreams struct
  function newFakeStreams (line 31) | func newFakeStreams(fake *FakeJetstreamV1beta2, namespace string) typedj...

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/generated_expansion.go
  type AccountExpansion (line 18) | type AccountExpansion interface
  type ConsumerExpansion (line 20) | type ConsumerExpansion interface
  type KeyValueExpansion (line 22) | type KeyValueExpansion interface
  type ObjectStoreExpansion (line 24) | type ObjectStoreExpansion interface
  type StreamExpansion (line 26) | type StreamExpansion interface

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/jetstream_client.go
  type JetstreamV1beta2Interface (line 26) | type JetstreamV1beta2Interface interface
  type JetstreamV1beta2Client (line 36) | type JetstreamV1beta2Client struct
    method Accounts (line 40) | func (c *JetstreamV1beta2Client) Accounts(namespace string) AccountInt...
    method Consumers (line 44) | func (c *JetstreamV1beta2Client) Consumers(namespace string) ConsumerI...
    method KeyValues (line 48) | func (c *JetstreamV1beta2Client) KeyValues(namespace string) KeyValueI...
    method ObjectStores (line 52) | func (c *JetstreamV1beta2Client) ObjectStores(namespace string) Object...
    method Streams (line 56) | func (c *JetstreamV1beta2Client) Streams(namespace string) StreamInter...
    method RESTClient (line 113) | func (c *JetstreamV1beta2Client) RESTClient() rest.Interface {
  function NewForConfig (line 63) | func NewForConfig(c *rest.Config) (*JetstreamV1beta2Client, error) {
  function NewForConfigAndClient (line 75) | func NewForConfigAndClient(c *rest.Config, h *http.Client) (*JetstreamV1...
  function NewForConfigOrDie (line 87) | func NewForConfigOrDie(c *rest.Config) *JetstreamV1beta2Client {
  function New (line 96) | func New(c rest.Interface) *JetstreamV1beta2Client {
  function setConfigDefaults (line 100) | func setConfigDefaults(config *rest.Config) {

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/keyvalue.go
  type KeyValuesGetter (line 32) | type KeyValuesGetter interface
  type KeyValueInterface (line 37) | type KeyValueInterface interface
  type keyValues (line 55) | type keyValues struct
  function newKeyValues (line 60) | func newKeyValues(c *JetstreamV1beta2Client, namespace string) *keyValues {

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/objectstore.go
  type ObjectStoresGetter (line 32) | type ObjectStoresGetter interface
  type ObjectStoreInterface (line 37) | type ObjectStoreInterface interface
  type objectStores (line 55) | type objectStores struct
  function newObjectStores (line 60) | func newObjectStores(c *JetstreamV1beta2Client, namespace string) *objec...

FILE: pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/stream.go
  type StreamsGetter (line 32) | type StreamsGetter interface
  type StreamInterface (line 37) | type StreamInterface interface
  type streams (line 55) | type streams struct
  function newStreams (line 60) | func newStreams(c *JetstreamV1beta2Client, namespace string) *streams {

FILE: pkg/jetstream/generated/informers/externalversions/factory.go
  type SharedInformerOption (line 33) | type SharedInformerOption
  type sharedInformerFactory (line 35) | type sharedInformerFactory struct
    method Start (line 121) | func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
    method Shutdown (line 145) | func (f *sharedInformerFactory) Shutdown() {
    method WaitForCacheSync (line 154) | func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{...
    method InformerFor (line 177) | func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFun...
    method Jetstream (line 257) | func (f *sharedInformerFactory) Jetstream() jetstream.Interface {
  function WithCustomResyncConfig (line 56) | func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) Sh...
  function WithTweakListOptions (line 66) | func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListO...
  function WithNamespace (line 74) | func WithNamespace(namespace string) SharedInformerOption {
  function WithTransform (line 82) | func WithTransform(transform cache.TransformFunc) SharedInformerOption {
  function NewSharedInformerFactory (line 90) | func NewSharedInformerFactory(client versioned.Interface, defaultResync ...
  function NewFilteredSharedInformerFactory (line 98) | func NewFilteredSharedInformerFactory(client versioned.Interface, defaul...
  function NewSharedInformerFactoryWithOptions (line 103) | func NewSharedInformerFactoryWithOptions(client versioned.Interface, def...
  type SharedInformerFactory (line 223) | type SharedInformerFactory interface

FILE: pkg/jetstream/generated/informers/externalversions/generic.go
  type GenericInformer (line 28) | type GenericInformer interface
  type genericInformer (line 33) | type genericInformer struct
    method Informer (line 39) | func (f *genericInformer) Informer() cache.SharedIndexInformer {
    method Lister (line 44) | func (f *genericInformer) Lister() cache.GenericLister {
  method ForResource (line 50) | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersion...

FILE: pkg/jetstream/generated/informers/externalversions/internalinterfaces/factory_interfaces.go
  type NewInformerFunc (line 28) | type NewInformerFunc
  type SharedInformerFactory (line 31) | type SharedInformerFactory interface
  type TweakListOptionsFunc (line 37) | type TweakListOptionsFunc

FILE: pkg/jetstream/generated/informers/externalversions/jetstream/interface.go
  type Interface (line 24) | type Interface interface
  type group (line 29) | type group struct
    method V1beta2 (line 41) | func (g *group) V1beta2() v1beta2.Interface {
  function New (line 36) | func New(f internalinterfaces.SharedInformerFactory, namespace string, t...

FILE: pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/account.go
  type AccountInformer (line 34) | type AccountInformer interface
  type accountInformer (line 39) | type accountInformer struct
    method defaultInformer (line 89) | func (f *accountInformer) defaultInformer(client versioned.Interface, ...
    method Informer (line 93) | func (f *accountInformer) Informer() cache.SharedIndexInformer {
    method Lister (line 97) | func (f *accountInformer) Lister() jetstreamv1beta2.AccountLister {
  function NewAccountInformer (line 48) | func NewAccountInformer(client versioned.Interface, namespace string, re...
  function NewFilteredAccountInformer (line 55) | func NewFilteredAccountInformer(client versioned.Interface, namespace st...

FILE: pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/consumer.go
  type ConsumerInformer (line 34) | type ConsumerInformer interface
  type consumerInformer (line 39) | type consumerInformer struct
    method defaultInformer (line 89) | func (f *consumerInformer) defaultInformer(client versioned.Interface,...
    method Informer (line 93) | func (f *consumerInformer) Informer() cache.SharedIndexInformer {
    method Lister (line 97) | func (f *consumerInformer) Lister() jetstreamv1beta2.ConsumerLister {
  function NewConsumerInformer (line 48) | func NewConsumerInformer(client versioned.Interface, namespace string, r...
  function NewFilteredConsumerInformer (line 55) | func NewFilteredConsumerInformer(client versioned.Interface, namespace s...

FILE: pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/interface.go
  type Interface (line 23) | type Interface interface
  type version (line 36) | type version struct
    method Accounts (line 48) | func (v *version) Accounts() AccountInformer {
    method Consumers (line 53) | func (v *version) Consumers() ConsumerInformer {
    method KeyValues (line 58) | func (v *version) KeyValues() KeyValueInformer {
    method ObjectStores (line 63) | func (v *version) ObjectStores() ObjectStoreInformer {
    method Streams (line 68) | func (v *version) Streams() StreamInformer {
  function New (line 43) | func New(f internalinterfaces.SharedInformerFactory, namespace string, t...

FILE: pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/keyvalue.go
  type KeyValueInformer (line 34) | type KeyValueInformer interface
  type keyValueInformer (line 39) | type keyValueInformer struct
    method defaultInformer (line 89) | func (f *keyValueInformer) defaultInformer(client versioned.Interface,...
    method Informer (line 93) | func (f *keyValueInformer) Informer() cache.SharedIndexInformer {
    method Lister (line 97) | func (f *keyValueInformer) Lister() jetstreamv1beta2.KeyValueLister {
  function NewKeyValueInformer (line 48) | func NewKeyValueInformer(client versioned.Interface, namespace string, r...
  function NewFilteredKeyValueInformer (line 55) | func NewFilteredKeyValueInformer(client versioned.Interface, namespace s...

FILE: pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/objectstore.go
  type ObjectStoreInformer (line 34) | type ObjectStoreInformer interface
  type objectStoreInformer (line 39) | type objectStoreInformer struct
    method defaultInformer (line 89) | func (f *objectStoreInformer) defaultInformer(client versioned.Interfa...
    method Informer (line 93) | func (f *objectStoreInformer) Informer() cache.SharedIndexInformer {
    method Lister (line 97) | func (f *objectStoreInformer) Lister() jetstreamv1beta2.ObjectStoreLis...
  function NewObjectStoreInformer (line 48) | func NewObjectStoreInformer(client versioned.Interface, namespace string...
  function NewFilteredObjectStoreInformer (line 55) | func NewFilteredObjectStoreInformer(client versioned.Interface, namespac...

FILE: pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/stream.go
  type StreamInformer (line 34) | type StreamInformer interface
  type streamInformer (line 39) | type streamInformer struct
    method defaultInformer (line 89) | func (f *streamInformer) defaultInformer(client versioned.Interface, r...
    method Informer (line 93) | func (f *streamInformer) Informer() cache.SharedIndexInformer {
    method Lister (line 97) | func (f *streamInformer) Lister() jetstreamv1beta2.StreamLister {
  function NewStreamInformer (line 48) | func NewStreamInformer(client versioned.Interface, namespace string, res...
  function NewFilteredStreamInformer (line 55) | func NewFilteredStreamInformer(client versioned.Interface, namespace str...

FILE: pkg/jetstream/generated/listers/jetstream/v1beta2/account.go
  type AccountLister (line 27) | type AccountLister interface
  type accountLister (line 37) | type accountLister struct
    method Accounts (line 47) | func (s *accountLister) Accounts(namespace string) AccountNamespaceLis...
  function NewAccountLister (line 42) | func NewAccountLister(indexer cache.Indexer) AccountLister {
  type AccountNamespaceLister (line 53) | type AccountNamespaceLister interface
  type accountNamespaceLister (line 65) | type accountNamespaceLister struct

FILE: pkg/jetstream/generated/listers/jetstream/v1beta2/consumer.go
  type ConsumerLister (line 27) | type ConsumerLister interface
  type consumerLister (line 37) | type consumerLister struct
    method Consumers (line 47) | func (s *consumerLister) Consumers(namespace string) ConsumerNamespace...
  function NewConsumerLister (line 42) | func NewConsumerLister(indexer cache.Indexer) ConsumerLister {
  type ConsumerNamespaceLister (line 53) | type ConsumerNamespaceLister interface
  type consumerNamespaceLister (line 65) | type consumerNamespaceLister struct

FILE: pkg/jetstream/generated/listers/jetstream/v1beta2/expansion_generated.go
  type AccountListerExpansion (line 20) | type AccountListerExpansion interface
  type AccountNamespaceListerExpansion (line 24) | type AccountNamespaceListerExpansion interface
  type ConsumerListerExpansion (line 28) | type ConsumerListerExpansion interface
  type ConsumerNamespaceListerExpansion (line 32) | type ConsumerNamespaceListerExpansion interface
  type KeyValueListerExpansion (line 36) | type KeyValueListerExpansion interface
  type KeyValueNamespaceListerExpansion (line 40) | type KeyValueNamespaceListerExpansion interface
  type ObjectStoreListerExpansion (line 44) | type ObjectStoreListerExpansion interface
  type ObjectStoreNamespaceListerExpansion (line 48) | type ObjectStoreNamespaceListerExpansion interface
  type StreamListerExpansion (line 52) | type StreamListerExpansion interface
  type StreamNamespaceListerExpansion (line 56) | type StreamNamespaceListerExpansion interface

FILE: pkg/jetstream/generated/listers/jetstream/v1beta2/keyvalue.go
  type KeyValueLister (line 27) | type KeyValueLister interface
  type keyValueLister (line 37) | type keyValueLister struct
    method KeyValues (line 47) | func (s *keyValueLister) KeyValues(namespace string) KeyValueNamespace...
  function NewKeyValueLister (line 42) | func NewKeyValueLister(indexer cache.Indexer) KeyValueLister {
  type KeyValueNamespaceLister (line 53) | type KeyValueNamespaceLister interface
  type keyValueNamespaceLister (line 65) | type keyValueNamespaceLister struct

FILE: pkg/jetstream/generated/listers/jetstream/v1beta2/objectstore.go
  type ObjectStoreLister (line 27) | type ObjectStoreLister interface
  type objectStoreLister (line 37) | type objectStoreLister struct
    method ObjectStores (line 47) | func (s *objectStoreLister) ObjectStores(namespace string) ObjectStore...
  function NewObjectStoreLister (line 42) | func NewObjectStoreLister(indexer cache.Indexer) ObjectStoreLister {
  type ObjectStoreNamespaceLister (line 53) | type ObjectStoreNamespaceLister interface
  type objectStoreNamespaceLister (line 65) | type objectStoreNamespaceLister struct

FILE: pkg/jetstream/generated/listers/jetstream/v1beta2/stream.go
  type StreamLister (line 27) | type StreamLister interface
  type streamLister (line 37) | type streamLister struct
    method Streams (line 47) | func (s *streamLister) Streams(namespace string) StreamNamespaceLister {
  function NewStreamLister (line 42) | func NewStreamLister(indexer cache.Indexer) StreamLister {
  type StreamNamespaceLister (line 53) | type StreamNamespaceLister interface
  type streamNamespaceLister (line 65) | type streamNamespaceLister struct

FILE: pkg/natsreloader/natsreloader.go
  constant errorFmt (line 36) | errorFmt = "Error: %s\n"
  function isInotifyExhausted (line 38) | func isInotifyExhausted(err error) bool {
  function createInotifyExhaustedError (line 50) | func createInotifyExhaustedError(originalErr error, watchedFileCount int...
  type Config (line 76) | type Config struct
  type Reloader (line 89) | type Reloader struct
    method waitForProcess (line 103) | func (r *Reloader) waitForProcess() error {
    method createWatcherWithRetry (line 247) | func (r *Reloader) createWatcherWithRetry() (*fsnotify.Watcher, error) {
    method init (line 286) | func (r *Reloader) init() (*fsnotify.Watcher, map[string][]byte, error) {
    method reload (line 366) | func (r *Reloader) reload(updatedFiles []string) error {
    method Run (line 395) | func (r *Reloader) Run(ctx context.Context) error {
    method Stop (line 473) | func (r *Reloader) Stop() error {
    method pollForChanges (line 495) | func (r *Reloader) pollForChanges(lastConfigAppliedCache map[string][]...
    method runPollingMode (line 529) | func (r *Reloader) runPollingMode(ctx context.Context) error {
  function removeDuplicateStrings (line 150) | func removeDuplicateStrings(s []string) []string {
  function getFileDigest (line 167) | func getFileDigest(filePath string) ([]byte, error) {
  function handleEvent (line 180) | func handleEvent(event fsnotify.Event, lastConfigAppliedCache map[string...
  function handleEvents (line 219) | func handleEvents(configWatcher *fsnotify.Watcher, event fsnotify.Event,...
  function handleDeletedFiles (line 231) | func handleDeletedFiles(deletedFiles []string, configWatcher *fsnotify.W...
  function NewReloader (line 480) | func NewReloader(config *Config) (*Reloader, error) {
  function retryJitter (line 488) | func retryJitter(base time.Duration) time.Duration {
  function getServerFiles (line 595) | func getServerFiles(configFile string) ([]string, error) {
  function getIncludePaths (line 612) | func getIncludePaths(configFile string, checked map[string]interface{}) ...
  function getCertPaths (line 664) | func getCertPaths(configPaths []string) ([]string, error) {

FILE: pkg/natsreloader/natsreloader_test.go
  constant testConfig_0 (line 33) | testConfig_0 = `
  constant testConfig_1 (line 56) | testConfig_1 = `include ./testConfig_2.conf`
  constant testConfig_2 (line 58) | testConfig_2 = `
  constant includeTest_0 (line 64) | includeTest_0 = `
  constant includeTest_1 (line 75) | includeTest_1 = `
  function TestReloader (line 98) | func TestReloader(t *testing.T) {
  function TestInclude (line 201) | func TestInclude(t *testing.T) {
  function TestFileFinder (line 268) | func TestFileFinder(t *testing.T) {
  function writeFile (line 363) | func writeFile(content, path string) error {
  function TestReloaderInotifyExhaustion (line 386) | func TestReloaderInotifyExhaustion(t *testing.T) {
  function TestReloaderPollingMode (line 459) | func TestReloaderPollingMode(t *testing.T) {
  function TestReloaderPollingModeFileDeletion (line 549) | func TestReloaderPollingModeFileDeletion(t *testing.T) {
Condensed preview — 177 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,029K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 326,
    "preview": "blank_issues_enabled: false\ncontact_links:\n  - name: Discussion\n    url: https://github.com/nats-io/nack/discussions\n   "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/defect.yml",
    "chars": 1316,
    "preview": "---\nname: Defect\ndescription: Report a defect, such as a bug or regression.\nlabels:\n  - defect\nbody:\n  - type: textarea\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/proposal.yml",
    "chars": 951,
    "preview": "---\nname: Proposal\ndescription: Propose an enhancement or new feature.\nlabels:\n  - proposal\nbody:\n  - type: textarea\n   "
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 735,
    "preview": "version: 2\nupdates:\n  # version updates: enabled\n  # security updates: enabled\n  - package-ecosystem: \"github-actions\"\n "
  },
  {
    "path": ".github/workflows/claude.yml",
    "chars": 1051,
    "preview": "name: Claude Code\n\n# GITHUB_TOKEN needs contents:read and actions:read — required by\n# claude-code-action for restoring "
  },
  {
    "path": ".github/workflows/deps-release-detect.yaml",
    "chars": 3035,
    "preview": "name: Deps Release\n\non: 'pull_request'\n\npermissions:\n  contents: write\n\njobs:\n  detect:\n    name: Detect\n    runs-on: ub"
  },
  {
    "path": ".github/workflows/deps-release-tag.yaml",
    "chars": 2488,
    "preview": "name: Deps Release\n\non:\n  push:\n    branches:\n      - main\n\npermissions:\n  actions: write\n  contents: write\n\njobs:\n  tag"
  },
  {
    "path": ".github/workflows/e2e.yaml",
    "chars": 887,
    "preview": "name: e2e\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n\njobs:\n  e2e:\n    name: e2e\n    runs-on: ubuntu-latest"
  },
  {
    "path": ".github/workflows/release.yaml",
    "chars": 1686,
    "preview": "name: Release\non:\n  workflow_dispatch:\n  push:\n    tags:\n      - v[0-9]+.[0-9]+.[0-9]+\njobs:\n  release:\n    runs-on: ubu"
  },
  {
    "path": ".github/workflows/test.yaml",
    "chars": 611,
    "preview": "name: Test\non:\n  push:\n    paths-ignore:\n      - '**.md'\n  pull_request:\n    paths-ignore:\n      - '**.md'\n\njobs:\n  test"
  },
  {
    "path": ".gitignore",
    "chars": 430,
    "preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, built with `go test -c`\n*.test\n\n# Ou"
  },
  {
    "path": ".goreleaser.yml",
    "chars": 1231,
    "preview": "version: 2\nproject_name: nack\n\nrelease:\n  name_template: 'Release {{.Tag}}'\n  draft: true\n  skip_upload: true\n  github:\n"
  },
  {
    "path": "CLAUDE.md",
    "chars": 3847,
    "preview": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## "
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1302,
    "preview": "> [!WARNING]\n> This contribution guide is work in progress and is meant to be a location where more developers can contr"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "Makefile",
    "chars": 7255,
    "preview": "export GO111MODULE := on\n\nSHELL=/usr/bin/env bash\n\nENVTEST_K8S_VERSION = 1.32.0\n\nnow := $(shell date -u +%Y-%m-%dT%H:%M:"
  },
  {
    "path": "README.md",
    "chars": 15463,
    "preview": "<img width=\"800\" alt=\"nack-large\" src=\"https://user-images.githubusercontent.com/26195/92535603-71ad9a80-f1ec-11ea-8959-"
  },
  {
    "path": "cicd/Dockerfile",
    "chars": 1221,
    "preview": "#syntax=docker/dockerfile:1.13\nARG GO_APP\n\nFROM alpine:3.23.3 AS deps\n\nARG GO_APP\nARG GORELEASER_DIST_DIR=/go/src/dist\n\n"
  },
  {
    "path": "cicd/Dockerfile_goreleaser",
    "chars": 712,
    "preview": "#syntax=docker/dockerfile:1.13\nFROM --platform=$BUILDPLATFORM golang:1.25.6-bookworm AS build\n\n\nRUN <<EOT\n    set -e\n\n  "
  },
  {
    "path": "cicd/assets/entrypoint.sh",
    "chars": 33,
    "preview": "#!/bin/sh\nexec \"/${GO_APP}\" \"$@\"\n"
  },
  {
    "path": "cicd/tag-deps-version.txt",
    "chars": 14,
    "preview": "0.21.0\n0.21.1\n"
  },
  {
    "path": "cmd/jetstream-controller/main.go",
    "chars": 7825,
    "preview": "// Copyright 2020-2023 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "cmd/nats-boot-config/main.go",
    "chars": 2269,
    "preview": "// Copyright 2018 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "cmd/nats-server-config-reloader/main.go",
    "chars": 3491,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/n"
  },
  {
    "path": "controllers/jetstream/conn_pool.go",
    "chars": 6016,
    "preview": "package jetstream\n\nimport (\n\t\"crypto/sha256\"\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\n\t\"github.com/nats-io/n"
  },
  {
    "path": "controllers/jetstream/conn_pool_test.go",
    "chars": 1678,
    "preview": "package jetstream\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nats-io/nats.go\"\n\n\tnatsservertest \"github.com/nats-"
  },
  {
    "path": "controllers/jetstream/consumer.go",
    "chars": 12646,
    "preview": "package jetstream\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/nats-io/jsm.go\"\n\tjsmapi \"github"
  },
  {
    "path": "controllers/jetstream/consumer_test.go",
    "chars": 12005,
    "preview": "package jetstream\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\tjsmapi \"github.com/nats-io/jsm.go/api\"\n"
  },
  {
    "path": "controllers/jetstream/controller.go",
    "chars": 24391,
    "preview": "// Copyright 2020-2022 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "controllers/jetstream/controller_test.go",
    "chars": 7980,
    "preview": "package jetstream\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\tjsmapi \"github.com/nats-io/jsm.go/api\"\n\tapis \"g"
  },
  {
    "path": "controllers/jetstream/jsmclient.go",
    "chars": 1914,
    "preview": "package jetstream\n\nimport (\n\t\"context\"\n\n\t\"github.com/nats-io/jsm.go\"\n\tjsmapi \"github.com/nats-io/jsm.go/api\"\n\t\"github.co"
  },
  {
    "path": "controllers/jetstream/jsmclient_test.go",
    "chars": 1796,
    "preview": "package jetstream\n\nimport (\n\t\"context\"\n\n\t\"github.com/nats-io/jsm.go\"\n\tjsmapi \"github.com/nats-io/jsm.go/api\"\n\t\"github.co"
  },
  {
    "path": "controllers/jetstream/stream.go",
    "chars": 16622,
    "preview": "// Copyright 2020 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "controllers/jetstream/stream_test.go",
    "chars": 7187,
    "preview": "package jetstream\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\n\tjsmapi \"github.com/nats-io/jsm.go/api\"\n\n\tapis \""
  },
  {
    "path": "dependencies.md",
    "chars": 812,
    "preview": "# External Dependencies\n\nThis file lists the dependencies used in this repository.\n\n| Dependency                        "
  },
  {
    "path": "deploy/crds.yml",
    "chars": 56350,
    "preview": "---\napiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n  name: streams.jetstream.nats.io\nspec:"
  },
  {
    "path": "deploy/examples/consumer_pull.yml",
    "chars": 246,
    "preview": "---\napiVersion: jetstream.nats.io/v1beta2\nkind: Consumer\nmetadata:\n  name: my-pull-consumer\nspec:\n  streamName: mystream"
  },
  {
    "path": "deploy/examples/consumer_push.yml",
    "chars": 342,
    "preview": "---\napiVersion: jetstream.nats.io/v1beta2\nkind: Consumer\nmetadata:\n  name: my-push-consumer\nspec:\n  streamName: mystream"
  },
  {
    "path": "deploy/examples/stream.yml",
    "chars": 172,
    "preview": "---\napiVersion: jetstream.nats.io/v1beta2\nkind: Stream\nmetadata:\n  name: mystream\nspec:\n  name: mystream\n  subjects: [\"o"
  },
  {
    "path": "deploy/examples/stream_mirror.yml",
    "chars": 257,
    "preview": "---\napiVersion: jetstream.nats.io/v1beta2\nkind: Stream\nmetadata:\n  name: mystream-mirror\nspec:\n  name: mystream-mirror\n "
  },
  {
    "path": "deploy/examples/stream_placement.yml",
    "chars": 177,
    "preview": "---\napiVersion: jetstream.nats.io/v1beta2\nkind: Stream\nmetadata:\n  name: mystream-placement\nspec:\n  name: mystream-place"
  },
  {
    "path": "deploy/examples/stream_servers.yml",
    "chars": 332,
    "preview": "apiVersion: jetstream.nats.io/v1beta2\nkind: Stream\nmetadata:\n  name: mystream\nspec:\n  name: mystream\n  servers:\n  - nats"
  },
  {
    "path": "deploy/examples/stream_sources.yml",
    "chars": 174,
    "preview": "---\napiVersion: jetstream.nats.io/v1beta2\nkind: Stream\nmetadata:\n  name: mystream-sources\nspec:\n  name: mystream-sources"
  },
  {
    "path": "deploy/rbac.yml",
    "chars": 1252,
    "preview": "---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: jetstream-controller\n  namespace: default\n---\napiVersion: rbac"
  },
  {
    "path": "docker-bake.hcl",
    "chars": 2352,
    "preview": "###################\n### Variables\n###################\n\nvariable REGISTRY {\n  default = \"\"\n}\n\n# Comma delimited list of t"
  },
  {
    "path": "docs/api.md",
    "chars": 90998,
    "preview": "# API Reference\n\nPackages:\n\n- [jetstream.nats.io/v1beta2](#jetstreamnatsiov1beta2)\n- [jetstream.nats.io/v1beta1](#jetstr"
  },
  {
    "path": "examples/secure/client-tls.yaml",
    "chars": 326,
    "preview": "---\napiVersion: cert-manager.io/v1\nkind: Certificate\nmetadata:\n  name: nats-sys-tls\nspec:\n  secretName: nats-sys-tls\n  d"
  },
  {
    "path": "examples/secure/issuer.yaml",
    "chars": 476,
    "preview": "---\napiVersion: cert-manager.io/v1\nkind: ClusterIssuer\nmetadata:\n  name: selfsigning\nspec:\n  selfSigned: {}\n---\napiVersi"
  },
  {
    "path": "examples/secure/nack/account-foo.yaml",
    "chars": 222,
    "preview": "---\napiVersion: jetstream.nats.io/v1beta2\nkind: Account\nmetadata:\n  name: a\nspec:\n  name: a\n  servers:\n  - nats://nats:4"
  },
  {
    "path": "examples/secure/nack/nats-account-a.yaml",
    "chars": 222,
    "preview": "---\napiVersion: jetstream.nats.io/v1beta2\nkind: Account\nmetadata:\n  name: a\nspec:\n  name: a\n  servers:\n  - nats://nats:4"
  },
  {
    "path": "examples/secure/nack/nats-consumer-bar-a.yaml",
    "chars": 157,
    "preview": "---\napiVersion: jetstream.nats.io/v1beta2\nkind: Consumer\nmetadata:\n  name: bar\nspec:\n  streamName: foo\n  durableName: ba"
  },
  {
    "path": "examples/secure/nack/nats-stream-foo-a.yaml",
    "chars": 167,
    "preview": "---\napiVersion: jetstream.nats.io/v1beta2\nkind: Stream\nmetadata:\n  name: foo\nspec:\n  name: foo\n  subjects: [\"foo\", \"foo."
  },
  {
    "path": "examples/secure/nack/stream-foo.yaml",
    "chars": 167,
    "preview": "---\napiVersion: jetstream.nats.io/v1beta2\nkind: Stream\nmetadata:\n  name: foo\nspec:\n  name: foo\n  subjects: [\"foo\", \"foo."
  },
  {
    "path": "examples/secure/nack-a-client-tls.yaml",
    "chars": 315,
    "preview": "---\napiVersion: cert-manager.io/v1\nkind: Certificate\nmetadata:\n  name: nack-a-tls\nspec:\n  secretName: nack-a-tls\n  durat"
  },
  {
    "path": "examples/secure/nack-b-client-tls.yaml",
    "chars": 315,
    "preview": "---\napiVersion: cert-manager.io/v1\nkind: Certificate\nmetadata:\n  name: nack-b-tls\nspec:\n  secretName: nack-b-tls\n  durat"
  },
  {
    "path": "examples/secure/nats-helm.yaml",
    "chars": 810,
    "preview": "tlsCA:\n  enabled: true\n  secretName: nats-sys-tls\n  key: ca.crt\n\nconfig:\n  cluster:\n    enabled: true\n  jetstream:\n    e"
  },
  {
    "path": "examples/secure/server-tls.yaml",
    "chars": 427,
    "preview": "---\napiVersion: cert-manager.io/v1\nkind: Certificate\nmetadata:\n  name: nats-server-tls\nspec:\n  secretName: nats-server-t"
  },
  {
    "path": "go.mod",
    "chars": 3847,
    "preview": "module github.com/nats-io/nack\n\ngo 1.25.0\n\nrequire (\n\tgithub.com/fsnotify/fsnotify v1.9.0\n\tgithub.com/go-logr/logr v1.4."
  },
  {
    "path": "go.sum",
    "chars": 23687,
    "preview": "github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=\ngithub.com/Masterminds/semver/v3"
  },
  {
    "path": "internal/controller/account_controller.go",
    "chars": 7663,
    "preview": "/*\nCopyright 2025.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "internal/controller/account_controller_test.go",
    "chars": 6274,
    "preview": "/*\nCopyright 2025.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "internal/controller/client.go",
    "chars": 5952,
    "preview": "package controller\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/nats-io/jsm.go\"\n\t\"gi"
  },
  {
    "path": "internal/controller/connection_pool.go",
    "chars": 1716,
    "preview": "package controller\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/nats-io/nats.go\"\n)\n\ntype pooledConnection struct {\n\tnc       "
  },
  {
    "path": "internal/controller/connection_pool_test.go",
    "chars": 1687,
    "preview": "package controller\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\tnatsservertest \"github.com/nats-io/nats-server/v2/test\"\n\t\"gith"
  },
  {
    "path": "internal/controller/consumer_controller.go",
    "chars": 16803,
    "preview": "/*\nCopyright 2025.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "internal/controller/consumer_controller_test.go",
    "chars": 35258,
    "preview": "/*\nCopyright 2025.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "internal/controller/helpers_test.go",
    "chars": 1171,
    "preview": "package controller\n\nimport (\n\t\"os\"\n\t\"time\"\n\n\tapi \"github.com/nats-io/nack/pkg/jetstream/apis/jetstream/v1beta2\"\n\t\"github"
  },
  {
    "path": "internal/controller/jetstream_controller.go",
    "chars": 12432,
    "preview": "package controller\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"str"
  },
  {
    "path": "internal/controller/jetstream_controller_test.go",
    "chars": 3542,
    "preview": "package controller\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\tapi \"github.com/nats-io/nack/pkg/jetstream/apis/jetstream/v1beta2\"\n\t\"g"
  },
  {
    "path": "internal/controller/keyvalue_controller.go",
    "chars": 13147,
    "preview": "/*\nCopyright 2025.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "internal/controller/keyvalue_controller_test.go",
    "chars": 28114,
    "preview": "/*\nCopyright 2025.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "internal/controller/objectstore_controller.go",
    "chars": 12518,
    "preview": "/*\nCopyright 2025.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "internal/controller/objectstore_controller_test.go",
    "chars": 26293,
    "preview": "/*\nCopyright 2025.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "internal/controller/register.go",
    "chars": 2110,
    "preview": "package controller\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\tctrl \"sigs.k8s.io/controller-runtime\"\n)\n\n// The Config contains parameters"
  },
  {
    "path": "internal/controller/stream_controller.go",
    "chars": 18796,
    "preview": "/*\nCopyright 2025.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "internal/controller/stream_controller_test.go",
    "chars": 35802,
    "preview": "/*\nCopyright 2025.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "internal/controller/suite_test.go",
    "chars": 3612,
    "preview": "/*\nCopyright 2025.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
  },
  {
    "path": "internal/controller/types.go",
    "chars": 651,
    "preview": "package controller\n\nconst (\n\treadyCondType        = \"Ready\"\n\taccountFinalizer     = \"account.nats.io/finalizer\"\n\tstreamF"
  },
  {
    "path": "kuttl-test.yaml",
    "chars": 138,
    "preview": "apiVersion: kuttl.dev/v1beta1\nkind: TestSuite\ntestDirs:\n  - tests/\ncommands:\n  - command: kubectl apply -f ./deploy/crds"
  },
  {
    "path": "pkg/bootconfig/bootconfig.go",
    "chars": 3990,
    "preview": "// Copyright 2018 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/register.go",
    "chars": 114,
    "preview": "package jetstream\n\n// GroupName is the group name used in this package\nconst (\n\tGroupName = \"jetstream.nats.io\"\n)\n"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta1/consumertypes.go",
    "chars": 1649,
    "preview": "package v1beta1\n\nimport (\n\tk8smeta \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\n// +genclient\n// +k8s:deepcopy-gen:interfac"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta1/doc.go",
    "chars": 122,
    "preview": "// +k8s:deepcopy-gen=package\n// +groupName=jetstream.nats.io\n\n// Package v1 is the v1 version of the API.\npackage v1beta"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta1/register.go",
    "chars": 1319,
    "preview": "package v1beta1\n\nimport (\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/api"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta1/streamtemplatetypes.go",
    "chars": 943,
    "preview": "package v1beta1\n\nimport (\n\tk8smeta \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\n// +genclient\n// +k8s:deepcopy-gen:interfac"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta1/streamtypes.go",
    "chars": 2399,
    "preview": "package v1beta1\n\nimport (\n\tk8smeta \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\n// +genclient\n// +k8s:deepcopy-gen:interfac"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta1/types.go",
    "chars": 614,
    "preview": "package v1beta1\n\nimport (\n\tk8sapi \"k8s.io/api/core/v1\"\n)\n\ntype CredentialsSecret struct {\n\tName string `json:\"name\"`\n\tKe"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta1/zz_generated.deepcopy.go",
    "chars": 10363,
    "preview": "//go:build !ignore_autogenerated\n// +build !ignore_autogenerated\n\n// Copyright 2025 The NATS Authors\n// Licensed under t"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta2/accounttypes.go",
    "chars": 1067,
    "preview": "package v1beta2\n\nimport (\n\tk8smeta \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\n// +genclient\n// +k8s:deepcopy-gen:interfac"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta2/consumertypes.go",
    "chars": 3389,
    "preview": "package v1beta2\n\nimport (\n\tk8smeta \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\n// +genclient\n// +k8s:deepcopy-gen:interfac"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta2/doc.go",
    "chars": 122,
    "preview": "// +k8s:deepcopy-gen=package\n// +groupName=jetstream.nats.io\n\n// Package v1 is the v1 version of the API.\npackage v1beta"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta2/keyvaluetypes.go",
    "chars": 1786,
    "preview": "package v1beta2\n\nimport (\n\t\"time\"\n\n\tk8smeta \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\n// +genclient\n// +k8s:deepcopy-gen"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta2/objectstoretypes.go",
    "chars": 1351,
    "preview": "package v1beta2\n\nimport (\n\tk8smeta \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\n// +genclient\n// +k8s:deepcopy-gen:interfac"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta2/register.go",
    "chars": 1379,
    "preview": "package v1beta2\n\nimport (\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/api"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta2/streamtypes.go",
    "chars": 4362,
    "preview": "package v1beta2\n\nimport (\n\tk8smeta \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\n// +genclient\n// +k8s:deepcopy-gen:interfac"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta2/types.go",
    "chars": 2128,
    "preview": "package v1beta2\n\nimport (\n\tk8sapi \"k8s.io/api/core/v1\"\n)\n\ntype CredentialsSecret struct {\n\tName string `json:\"name\"`\n\tKe"
  },
  {
    "path": "pkg/jetstream/apis/jetstream/v1beta2/zz_generated.deepcopy.go",
    "chars": 23684,
    "preview": "//go:build !ignore_autogenerated\n// +build !ignore_autogenerated\n\n// Copyright 2025 The NATS Authors\n// Licensed under t"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/internal/internal.go",
    "chars": 1522,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/account.go",
    "chars": 11759,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/accountspec.go",
    "chars": 3969,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/basestreamconfig.go",
    "chars": 2079,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/condition.go",
    "chars": 3457,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/connectionopts.go",
    "chars": 4409,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/consumer.go",
    "chars": 11811,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/consumerlimits.go",
    "chars": 2092,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/consumerspec.go",
    "chars": 18029,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/credssecret.go",
    "chars": 1980,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/keyvalue.go",
    "chars": 11811,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/keyvaluespec.go",
    "chars": 8312,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/nkeysecret.go",
    "chars": 1968,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/objectstore.go",
    "chars": 11967,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/objectstorespec.go",
    "chars": 5773,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/republish.go",
    "chars": 2418,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/secretref.go",
    "chars": 1452,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/status.go",
    "chars": 2200,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/stream.go",
    "chars": 11707,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/streamplacement.go",
    "chars": 2039,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/streamsource.go",
    "chars": 5071,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/streamspec.go",
    "chars": 20670,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/subjecttransform.go",
    "chars": 1977,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/tls.go",
    "chars": 2390,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/tlssecret.go",
    "chars": 2935,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/tokensecret.go",
    "chars": 1986,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/jetstream/v1beta2/user.go",
    "chars": 2364,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/applyconfiguration/utils.go",
    "chars": 4554,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/clientset.go",
    "chars": 3902,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/fake/clientset_generated.go",
    "chars": 4627,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/fake/doc.go",
    "chars": 711,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/fake/register.go",
    "chars": 1881,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/scheme/doc.go",
    "chars": 727,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/scheme/register.go",
    "chars": 1937,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/account.go",
    "chars": 3665,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/consumer.go",
    "chars": 3711,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/doc.go",
    "chars": 713,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/doc.go",
    "chars": 704,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_account.go",
    "chars": 2039,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_consumer.go",
    "chars": 2062,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_jetstream_client.go",
    "chars": 1741,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_keyvalue.go",
    "chars": 2062,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_objectstore.go",
    "chars": 2131,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/fake/fake_stream.go",
    "chars": 2009,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/generated_expansion.go",
    "chars": 830,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/jetstream_client.go",
    "chars": 3749,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/keyvalue.go",
    "chars": 3711,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/objectstore.go",
    "chars": 3849,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/clientset/versioned/typed/jetstream/v1beta2/stream.go",
    "chars": 3619,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/informers/externalversions/factory.go",
    "chars": 9299,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/informers/externalversions/generic.go",
    "chars": 2776,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/informers/externalversions/internalinterfaces/factory_interfaces.go",
    "chars": 1456,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/informers/externalversions/jetstream/interface.go",
    "chars": 1665,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/account.go",
    "chars": 4263,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/consumer.go",
    "chars": 4287,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/interface.go",
    "chars": 2678,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/keyvalue.go",
    "chars": 4287,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/objectstore.go",
    "chars": 4359,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/informers/externalversions/jetstream/v1beta2/stream.go",
    "chars": 4239,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/listers/jetstream/v1beta2/account.go",
    "chars": 2666,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/listers/jetstream/v1beta2/consumer.go",
    "chars": 2706,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/listers/jetstream/v1beta2/expansion_generated.go",
    "chars": 2035,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/listers/jetstream/v1beta2/keyvalue.go",
    "chars": 2706,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/listers/jetstream/v1beta2/objectstore.go",
    "chars": 2826,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/jetstream/generated/listers/jetstream/v1beta2/stream.go",
    "chars": 2626,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/k8scodegen/file-header.txt",
    "chars": 586,
    "preview": "// Copyright 2025 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use"
  },
  {
    "path": "pkg/k8scodegen/k8scodegen.go",
    "chars": 53,
    "preview": "package k8scodegen\n\nimport _ \"k8s.io/code-generator\"\n"
  },
  {
    "path": "pkg/natsreloader/natsreloader.go",
    "chars": 18926,
    "preview": "// Copyright 2020-2023 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "pkg/natsreloader/natsreloader_test.go",
    "chars": 15936,
    "preview": "// Copyright 2020-2023 The NATS Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may no"
  },
  {
    "path": "tests/Dockerfile",
    "chars": 1628,
    "preview": "# This Dockerfile enables straight-forward building of the jetstream-controller\n# This is currently not used in the CI/C"
  },
  {
    "path": "tests/nack-control-loop.yaml",
    "chars": 199,
    "preview": "jetstream:\n  enabled: true\n\n  image:\n    repository: nack\n    tag: test\n\n  # Enable controller-runtime mode\n  additional"
  },
  {
    "path": "tests/nack-legacy.yaml",
    "chars": 124,
    "preview": "jetstream:\n  enabled: true\n\n  image:\n    repository: nack\n    tag: test\n\n  nats:\n   url: nats://nats:4222\n\nnamespaced: t"
  },
  {
    "path": "tests/nats.yaml",
    "chars": 323,
    "preview": "---\nglobal:\n  labels:\n    app: main-jetstream\n\nnatsBox:\n  enabled: false\n\nconfig:\n  cluster:\n    enabled: false\n\n  gatew"
  },
  {
    "path": "tests/stream-creation/00-nack.yaml",
    "chars": 526,
    "preview": "apiVersion: kuttl.dev/v1beta1\nkind: TestStep\nunitTest: false\ncommands:\n  - command: helm uninstall --namespace $NAMESPAC"
  },
  {
    "path": "tests/stream-creation/01-stream.yaml",
    "chars": 129,
    "preview": "apiVersion: kuttl.dev/v1beta1\nkind: TestStep\napply:\n  - rides-stream.yaml\nassert:\n  - asserted-rides-stream.yaml\nunitTes"
  },
  {
    "path": "tests/stream-creation/02-natscli-stream.yaml",
    "chars": 119,
    "preview": "apiVersion: kuttl.dev/v1beta1\nkind: TestStep\napply:\n  - natscli.yaml\nassert:\n  - asserted-natscli.yaml\nunitTest: false\n"
  },
  {
    "path": "tests/stream-creation/asserted-natscli.yaml",
    "chars": 105,
    "preview": "apiVersion: v1\nkind: Pod\nmetadata:\n  labels:\n    run: natscli\n  name: natscli\nstatus:\n  phase: Succeeded\n"
  },
  {
    "path": "tests/stream-creation/asserted-rides-stream.yaml",
    "chars": 563,
    "preview": "apiVersion: jetstream.nats.io/v1beta2\nkind: Stream\nmetadata:\n  name: rides\nspec:\n  allowDirect: false\n  allowMsgTtl: fal"
  },
  {
    "path": "tests/stream-creation/natscli.yaml",
    "chars": 280,
    "preview": "apiVersion: v1\nkind: Pod\nmetadata:\n  labels:\n    run: natscli\n  name: natscli\nspec:\n  restartPolicy: Never\n  containers:"
  },
  {
    "path": "tests/stream-creation/rides-stream.yaml",
    "chars": 155,
    "preview": "apiVersion: jetstream.nats.io/v1beta2\nkind: Stream\nmetadata:\n  name: rides\nspec:\n  name: rides\n  subjects:\n    - \"rides."
  }
]

About this extraction

This page contains the full source code of the nats-io/nack GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 177 files (926.2 KB), approximately 251.3k tokens, and a symbol index with 916 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!