diff --git a/go.mod b/go.mod index 1994cbdecd..c13dc1c004 100644 --- a/go.mod +++ b/go.mod @@ -56,7 +56,7 @@ require ( github.com/mna/pigeon v1.3.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/nats-io/nats-server/v2 v2.12.6 - github.com/nats-io/nats.go v1.49.0 + github.com/nats-io/nats.go v1.50.0 github.com/oklog/run v1.2.0 github.com/olekukonko/tablewriter v1.1.4 github.com/onsi/ginkgo v1.16.5 @@ -259,7 +259,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/juliangruber/go-intersect v1.1.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.18.4 // indirect + github.com/klauspost/compress v1.18.5 // indirect github.com/klauspost/cpuid/v2 v2.2.11 // indirect github.com/klauspost/crc32 v1.3.0 // indirect github.com/kovidgoyal/go-parallel v1.1.1 // indirect diff --git a/go.sum b/go.sum index d78a59a883..e8796772da 100644 --- a/go.sum +++ b/go.sum @@ -721,8 +721,8 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= -github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= +github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU= github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= @@ -904,8 +904,8 @@ github.com/nats-io/jwt/v2 v2.8.1 h1:V0xpGuD/N8Mi+fQNDynXohVvp7ZztevW5io8CUWlPmU= github.com/nats-io/jwt/v2 v2.8.1/go.mod h1:nWnOEEiVMiKHQpnAy4eXlizVEtSfzacZ1Q43LIRavZg= github.com/nats-io/nats-server/v2 v2.12.6 h1:Egbx9Vl7Ch8wTtpXPGqbehkZ+IncKqShUxvrt1+Enc8= github.com/nats-io/nats-server/v2 v2.12.6/go.mod h1:4HPlrvtmSO3yd7KcElDNMx9kv5EBJBnJJzQPptXlheo= -github.com/nats-io/nats.go v1.49.0 h1:yh/WvY59gXqYpgl33ZI+XoVPKyut/IcEaqtsiuTJpoE= -github.com/nats-io/nats.go v1.49.0/go.mod h1:fDCn3mN5cY8HooHwE2ukiLb4p4G4ImmzvXyJt+tGwdw= +github.com/nats-io/nats.go v1.50.0 h1:5zAeQrTvyrKrWLJ0fu02W3br8ym57qf7csDzgLOpcds= +github.com/nats-io/nats.go v1.50.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= diff --git a/vendor/github.com/klauspost/compress/.goreleaser.yml b/vendor/github.com/klauspost/compress/.goreleaser.yml index 4528059ca6..804a201816 100644 --- a/vendor/github.com/klauspost/compress/.goreleaser.yml +++ b/vendor/github.com/klauspost/compress/.goreleaser.yml @@ -31,6 +31,9 @@ builds: - mips64le goarm: - 7 + ignore: + - goos: windows + goarch: arm - id: "s2d" binary: s2d @@ -57,6 +60,9 @@ builds: - mips64le goarm: - 7 + ignore: + - goos: windows + goarch: arm - id: "s2sx" binary: s2sx @@ -84,6 +90,9 @@ builds: - mips64le goarm: - 7 + ignore: + - goos: windows + goarch: arm archives: - @@ -91,7 +100,7 @@ archives: name_template: "s2-{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" format_overrides: - goos: windows - format: zip + formats: ['zip'] files: - unpack/* - s2/LICENSE diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md index 5125c1f267..e839fe9c60 100644 --- a/vendor/github.com/klauspost/compress/README.md +++ b/vendor/github.com/klauspost/compress/README.md @@ -26,6 +26,12 @@ This package will support the current Go version and 2 versions back. Use the links above for more information on each. # changelog + +* Feb 9th, 2026 [1.18.4](https://github.com/klauspost/compress/releases/tag/v1.18.4) + * gzhttp: Add zstandard to server handler wrapper https://github.com/klauspost/compress/pull/1121 + * zstd: Add ResetWithOptions to encoder/decoder https://github.com/klauspost/compress/pull/1122 + * gzhttp: preserve qvalue when extra parameters follow in Accept-Encoding by @analytically in https://github.com/klauspost/compress/pull/1116 + * Jan 16th, 2026 [1.18.3](https://github.com/klauspost/compress/releases/tag/v1.18.3) * Downstream CVE-2025-61728. See [golang/go#77102](https://github.com/golang/go/issues/77102). @@ -691,3 +697,4 @@ This code is licensed under the same conditions as the original Go code. See LIC + diff --git a/vendor/github.com/klauspost/compress/flate/huffman_code.go b/vendor/github.com/klauspost/compress/flate/huffman_code.go index 5f901bd0fe..4b312dea3e 100644 --- a/vendor/github.com/klauspost/compress/flate/huffman_code.go +++ b/vendor/github.com/klauspost/compress/flate/huffman_code.go @@ -407,8 +407,8 @@ func histogramSplit(b []byte, h []uint16) { for i, t := range x { v0 := &h[t] v1 := &h[y[i]] - v3 := &h[w[i]] v2 := &h[z[i]] + v3 := &h[w[i]] *v0++ *v1++ *v2++ diff --git a/vendor/github.com/klauspost/compress/flate/regmask_other.go b/vendor/github.com/klauspost/compress/flate/regmask_other.go index 1b7a2cbd79..e62caf711e 100644 --- a/vendor/github.com/klauspost/compress/flate/regmask_other.go +++ b/vendor/github.com/klauspost/compress/flate/regmask_other.go @@ -1,5 +1,4 @@ //go:build !amd64 -// +build !amd64 package flate diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go index 99ddd4af97..2d6ef64be1 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go +++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go @@ -1,5 +1,4 @@ //go:build amd64 && !appengine && !noasm && gc -// +build amd64,!appengine,!noasm,gc // This file contains the specialisation of Decoder.Decompress4X // and Decoder.Decompress1X that use an asm implementation of thir main loops. diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_generic.go b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go index 908c17de63..6103923222 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress_generic.go +++ b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go @@ -1,5 +1,4 @@ //go:build !amd64 || appengine || !gc || noasm -// +build !amd64 appengine !gc noasm // This file contains a generic implementation of Decoder.Decompress4X. package huff0 diff --git a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go index e802579c4f..b97f9056f4 100644 --- a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go +++ b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go @@ -1,5 +1,4 @@ //go:build amd64 && !appengine && !noasm && gc -// +build amd64,!appengine,!noasm,gc package cpuinfo diff --git a/vendor/github.com/klauspost/compress/s2/decode_other.go b/vendor/github.com/klauspost/compress/s2/decode_other.go index c99d40b69d..2905ba2774 100644 --- a/vendor/github.com/klauspost/compress/s2/decode_other.go +++ b/vendor/github.com/klauspost/compress/s2/decode_other.go @@ -4,7 +4,6 @@ // license that can be found in the LICENSE file. //go:build (!amd64 && !arm64) || appengine || !gc || noasm -// +build !amd64,!arm64 appengine !gc noasm package s2 diff --git a/vendor/github.com/klauspost/compress/s2/encode_amd64.go b/vendor/github.com/klauspost/compress/s2/encode_amd64.go index 7aadd255fe..68d72a41d3 100644 --- a/vendor/github.com/klauspost/compress/s2/encode_amd64.go +++ b/vendor/github.com/klauspost/compress/s2/encode_amd64.go @@ -1,5 +1,4 @@ //go:build !appengine && !noasm && gc -// +build !appengine,!noasm,gc package s2 diff --git a/vendor/github.com/klauspost/compress/s2/encode_go.go b/vendor/github.com/klauspost/compress/s2/encode_go.go index e25b78445d..5597f3ef2e 100644 --- a/vendor/github.com/klauspost/compress/s2/encode_go.go +++ b/vendor/github.com/klauspost/compress/s2/encode_go.go @@ -1,5 +1,4 @@ //go:build !amd64 || appengine || !gc || noasm -// +build !amd64 appengine !gc noasm package s2 diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go index fd35ea1480..0e33aea442 100644 --- a/vendor/github.com/klauspost/compress/zstd/blockenc.go +++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go @@ -78,6 +78,7 @@ func (b *blockEnc) initNewEncode() { b.recentOffsets = [3]uint32{1, 4, 8} b.litEnc.Reuse = huff0.ReusePolicyNone b.coders.setPrev(nil, nil, nil) + b.dictLitEnc = nil } // reset will reset the block for a new encode, but in the same stream, diff --git a/vendor/github.com/klauspost/compress/zstd/enc_base.go b/vendor/github.com/klauspost/compress/zstd/enc_base.go index c1192ec38f..c4de134a7a 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_base.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_base.go @@ -21,7 +21,7 @@ type fastBase struct { crc *xxhash.Digest tmp [8]byte blk *blockEnc - lastDictID uint32 + lastDict *dict lowMem bool } diff --git a/vendor/github.com/klauspost/compress/zstd/enc_best.go b/vendor/github.com/klauspost/compress/zstd/enc_best.go index c1581cfcb8..851799322b 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_best.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_best.go @@ -479,10 +479,13 @@ func (e *bestFastEncoder) Reset(d *dict, singleBlock bool) { if d == nil { return } + dictChanged := d != e.lastDict // Init or copy dict table - if len(e.dictTable) != len(e.table) || d.id != e.lastDictID { + if len(e.dictTable) != len(e.table) || dictChanged { if len(e.dictTable) != len(e.table) { e.dictTable = make([]prevEntry, len(e.table)) + } else { + clear(e.dictTable) } end := int32(len(d.content)) - 8 + e.maxMatchOff for i := e.maxMatchOff; i < end; i += 4 { @@ -510,13 +513,14 @@ func (e *bestFastEncoder) Reset(d *dict, singleBlock bool) { offset: i + 3, } } - e.lastDictID = d.id } - // Init or copy dict table - if len(e.dictLongTable) != len(e.longTable) || d.id != e.lastDictID { + // Init or copy dict long table + if len(e.dictLongTable) != len(e.longTable) || dictChanged { if len(e.dictLongTable) != len(e.longTable) { e.dictLongTable = make([]prevEntry, len(e.longTable)) + } else { + clear(e.dictLongTable) } if len(d.content) >= 8 { cv := load6432(d.content, 0) @@ -538,8 +542,8 @@ func (e *bestFastEncoder) Reset(d *dict, singleBlock bool) { off++ } } - e.lastDictID = d.id } + e.lastDict = d // Reset table to initial state copy(e.longTable[:], e.dictLongTable) diff --git a/vendor/github.com/klauspost/compress/zstd/enc_better.go b/vendor/github.com/klauspost/compress/zstd/enc_better.go index 85dcd28c32..3305f09248 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_better.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_better.go @@ -1102,10 +1102,13 @@ func (e *betterFastEncoderDict) Reset(d *dict, singleBlock bool) { if d == nil { return } + dictChanged := d != e.lastDict // Init or copy dict table - if len(e.dictTable) != len(e.table) || d.id != e.lastDictID { + if len(e.dictTable) != len(e.table) || dictChanged { if len(e.dictTable) != len(e.table) { e.dictTable = make([]tableEntry, len(e.table)) + } else { + clear(e.dictTable) } end := int32(len(d.content)) - 8 + e.maxMatchOff for i := e.maxMatchOff; i < end; i += 4 { @@ -1133,14 +1136,15 @@ func (e *betterFastEncoderDict) Reset(d *dict, singleBlock bool) { offset: i + 3, } } - e.lastDictID = d.id e.allDirty = true } - // Init or copy dict table - if len(e.dictLongTable) != len(e.longTable) || d.id != e.lastDictID { + // Init or copy dict long table + if len(e.dictLongTable) != len(e.longTable) || dictChanged { if len(e.dictLongTable) != len(e.longTable) { e.dictLongTable = make([]prevEntry, len(e.longTable)) + } else { + clear(e.dictLongTable) } if len(d.content) >= 8 { cv := load6432(d.content, 0) @@ -1162,9 +1166,9 @@ func (e *betterFastEncoderDict) Reset(d *dict, singleBlock bool) { off++ } } - e.lastDictID = d.id e.allDirty = true } + e.lastDict = d // Reset table to initial state { diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go index cf8cad00dc..2fb6da112b 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go @@ -1040,15 +1040,18 @@ func (e *doubleFastEncoder) Reset(d *dict, singleBlock bool) { // ResetDict will reset and set a dictionary if not nil func (e *doubleFastEncoderDict) Reset(d *dict, singleBlock bool) { allDirty := e.allDirty + dictChanged := d != e.lastDict e.fastEncoderDict.Reset(d, singleBlock) if d == nil { return } // Init or copy dict table - if len(e.dictLongTable) != len(e.longTable) || d.id != e.lastDictID { + if len(e.dictLongTable) != len(e.longTable) || dictChanged { if len(e.dictLongTable) != len(e.longTable) { e.dictLongTable = make([]tableEntry, len(e.longTable)) + } else { + clear(e.dictLongTable) } if len(d.content) >= 8 { cv := load6432(d.content, 0) @@ -1065,7 +1068,6 @@ func (e *doubleFastEncoderDict) Reset(d *dict, singleBlock bool) { } } } - e.lastDictID = d.id allDirty = true } // Reset table to initial state diff --git a/vendor/github.com/klauspost/compress/zstd/enc_fast.go b/vendor/github.com/klauspost/compress/zstd/enc_fast.go index 9180a3a582..5e104f1a48 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_fast.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_fast.go @@ -805,9 +805,11 @@ func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) { } // Init or copy dict table - if len(e.dictTable) != len(e.table) || d.id != e.lastDictID { + if len(e.dictTable) != len(e.table) || d != e.lastDict { if len(e.dictTable) != len(e.table) { e.dictTable = make([]tableEntry, len(e.table)) + } else { + clear(e.dictTable) } if true { end := e.maxMatchOff + int32(len(d.content)) - 8 @@ -827,7 +829,7 @@ func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) { } } } - e.lastDictID = d.id + e.lastDict = d e.allDirty = true } diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go index 19e730acc2..0f2a00a003 100644 --- a/vendor/github.com/klauspost/compress/zstd/encoder.go +++ b/vendor/github.com/klauspost/compress/zstd/encoder.go @@ -138,11 +138,18 @@ func (e *Encoder) Reset(w io.Writer) { func (e *Encoder) ResetWithOptions(w io.Writer, opts ...EOption) error { e.o.resetOpt = true defer func() { e.o.resetOpt = false }() + hadDict := e.o.dict != nil for _, o := range opts { if err := o(&e.o); err != nil { return err } } + hasDict := e.o.dict != nil + if hadDict != hasDict { + // Dict presence changed — encoder type must be recreated. + e.state.encoder = nil + e.init = sync.Once{} + } e.Reset(w) return nil } @@ -448,6 +455,12 @@ func (e *Encoder) Close() error { if s.encoder == nil { return nil } + if s.w == nil { + if len(s.filling) == 0 && !s.headerWritten && !s.eofWritten && s.nInput == 0 { + return nil + } + return errors.New("zstd: encoder has no writer") + } err := e.nextBlock(true) if err != nil { if errors.Is(s.err, ErrEncoderClosed) { diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go index 8e0f5cac71..e217be0a17 100644 --- a/vendor/github.com/klauspost/compress/zstd/encoder_options.go +++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go @@ -42,6 +42,7 @@ func (o *encoderOptions) setDefault() { level: SpeedDefault, allLitEntropy: false, lowMem: false, + fullZero: true, } } diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go index d04a829b0a..b8c8607b5d 100644 --- a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go +++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go @@ -1,5 +1,4 @@ //go:build amd64 && !appengine && !noasm && gc -// +build amd64,!appengine,!noasm,gc package zstd diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go index 8adfebb029..2138f8091a 100644 --- a/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go +++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go @@ -1,5 +1,4 @@ //go:build !amd64 || appengine || !gc || noasm -// +build !amd64 appengine !gc noasm package zstd diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go index 0be16cefc7..9576426e68 100644 --- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go @@ -1,5 +1,4 @@ //go:build (!amd64 && !arm64) || appengine || !gc || purego || noasm -// +build !amd64,!arm64 appengine !gc purego noasm package xxhash diff --git a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go index f41932b7a4..1ed18927f9 100644 --- a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go +++ b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go @@ -1,5 +1,4 @@ //go:build amd64 && !appengine && !noasm && gc -// +build amd64,!appengine,!noasm,gc // Copyright 2019+ Klaus Post. All rights reserved. // License information can be found in the LICENSE file. diff --git a/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go b/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go index bea1779e97..379746c96c 100644 --- a/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go +++ b/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go @@ -1,5 +1,4 @@ //go:build !amd64 || appengine || !gc || noasm -// +build !amd64 appengine !gc noasm // Copyright 2019+ Klaus Post. All rights reserved. // License information can be found in the LICENSE file. diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go index 1f8c3cec28..18c3703ddc 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go @@ -1,5 +1,4 @@ //go:build amd64 && !appengine && !noasm && gc -// +build amd64,!appengine,!noasm,gc package zstd diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go b/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go index 7cec2197cd..516cd9b070 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go @@ -1,5 +1,4 @@ //go:build !amd64 || appengine || !gc || noasm -// +build !amd64 appengine !gc noasm package zstd diff --git a/vendor/github.com/nats-io/nats.go/CLAUDE.md b/vendor/github.com/nats-io/nats.go/CLAUDE.md new file mode 100644 index 0000000000..074da288e4 --- /dev/null +++ b/vendor/github.com/nats-io/nats.go/CLAUDE.md @@ -0,0 +1,147 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Official Go client library for the NATS messaging system. Provides core pub/sub, request/reply, JetStream (streams, consumers, KV, object store), and a micro services framework. Module path: `github.com/nats-io/nats.go`. + +## Build and Test Commands + +This project uses a **dual module** setup: `go.mod` for production (minimal deps) and `go_test.mod` for testing (includes nats-server, protobuf). Always use `-modfile=go_test.mod` when running tests or any command that needs test dependencies. + +```bash +# Build +go build ./... + +# Run all tests (race detector + internal_testing tag, sequential) +go test -modfile=go_test.mod -race -v -p=1 ./... --failfast -vet=off -tags=internal_testing + +# Run NoRace tests (must be run separately, without -race flag) +go test -modfile=go_test.mod -v -run=TestNoRace -p=1 ./... --failfast -vet=off + +# Run a specific test +go test -modfile=go_test.mod -race -run TestName ./... -tags=internal_testing + +# Run tests for a specific package +go test -modfile=go_test.mod -race ./jetstream/... --failfast +go test -modfile=go_test.mod -race ./micro/... --failfast + +# Coverage +./scripts/cov.sh + +# Formatting +go fmt ./... + +# Vet +go vet -modfile=go_test.mod ./... + +# Static analysis (as CI does it) +staticcheck -modfile=go_test.mod ./... + +# Linting (golangci-lint runs only on jetstream/) +golangci-lint run --timeout 5m0s ./jetstream/... + +# Spell check +find . -type f -name "*.go" | xargs misspell -error -locale US + +# Update test dependencies (never change go.mod for test deps) +go mod tidy -modfile=go_test.mod +``` + +## Important Build Tags + +- **`internal_testing`** -- Exposes internal test helpers (e.g., `AddMsgFilter`, `CloseTCPConn`) from `testing_internal.go`. Required for many tests in `./test/`. +- **`skip_no_race_tests`** -- Skips the NoRace tests. Used by coverage scripts. +- **`!race && !skip_no_race_tests`** -- NoRace tests in `test/norace_test.go` only run when the race detector is OFF. +- **`compat`** -- Compatibility tests in `test/compat_test.go`. + +## CI Pipeline (ci.yaml) + +1. **lint** -- `go fmt`, `go vet`, `staticcheck`, `misspell` (all packages), `golangci-lint` (jetstream only). +2. **test** -- Matrix of Go 1.24 and 1.25. Runs NoRace tests first (`-run=TestNoRace` without `-race`), then full race-enabled tests with `-tags=internal_testing`. + +## Project Structure + +``` +nats.go # Core connection, pub/sub, request/reply (~6500 lines) +parser.go # Client-side protocol parser +ws.go # WebSocket transport support +js.go # Legacy JetStream API (deprecated, see jetstream/) +jsm.go # Legacy JetStream management +kv.go # Legacy KeyValue API +object.go # Legacy Object Store API +enc.go # EncodedConn (deprecated) +netchan.go # Go channel bindings +timer.go # Internal timer utilities +context.go # Context-aware request methods +nats_iter.go # Go 1.23+ iterator support (go:build go1.23) +testing_internal.go # Internal test hooks (go:build internal_testing) + +jetstream/ # New JetStream API (preferred over legacy) + jetstream.go # Top-level JetStream interface + stream.go # Stream management + stream_config.go # Stream configuration types + consumer.go # Consumer management + consumer_config.go # Consumer configuration types + pull.go # Pull consumer implementation + push.go # Push consumer (deprecated) + ordered.go # Ordered consumer + publish.go # JetStream publish methods + kv.go # KeyValue store + object.go # Object store + message.go # JetStream message types + errors.go # JetStream error types + test/ # Integration tests (package test, uses nats-server) + +micro/ # Micro services framework + service.go # Service interface and implementation + request.go # Request handling + test/ # Integration tests + +internal/ + parser/ # NATS protocol parser (used by core client) + syncx/ # Concurrent map utility + +encoders/ + builtin/ # Default encoders (JSON, GOB, string) + protobuf/ # Protocol Buffers encoder + +test/ # Integration tests for core package (package test) + helper_test.go # Server setup helpers (RunDefaultServer, RunBasicJetStreamServer, etc.) + norace_test.go # Tests that cannot run with -race (build tag guarded) + js_internal_test.go # Tests requiring internal_testing tag + configs/ # NATS server config files for tests + +bench/ # Benchmarking utilities +examples/ # Example command-line tools (nats-pub, nats-sub, etc.) +scripts/cov.sh # Coverage collection script +``` + +## Test Architecture + +- **Root `nats_test.go`** (package `nats`) -- White-box unit tests with access to unexported internals. +- **`test/`** (package `test`) -- Black-box integration tests. Tests start an embedded nats-server using helpers from `test/helper_test.go`. These require `-modfile=go_test.mod` since nats-server is a test-only dependency. +- **`jetstream/test/`** (package `test`) -- Integration tests for the new JetStream API, also use embedded nats-server. +- **`micro/test/`** (package `test`) -- Integration tests for the micro services framework. +- **NoRace tests** -- Prefixed `TestNoRace*`, guarded by `//go:build !race && !skip_no_race_tests`. Must be run separately without `-race`. +- Tests always run with `-p=1` (no parallel packages) because they start embedded servers on shared ports. + +## Code Conventions + +- **License header** -- Every `.go` file starts with the Apache 2.0 license header (Copyright year range). +- **Error variables** -- Exported errors defined as `var Err... = errors.New("nats: ...")` in `nats.go`. JetStream errors in `jetstream/errors.go` follow the same pattern. +- **Options pattern** -- Connection options use functional options: `nats.Connect(url, nats.Name("myapp"), nats.MaxReconnects(5))`. JetStream and micro use similar patterns. +- **No external dependencies in production** -- Only `klauspost/compress`, `nkeys`, `nuid` in `go.mod`. Test deps (nats-server, protobuf) are isolated in `go_test.mod`. PRs adding dependencies are scrutinized heavily. +- **Commits require sign-off** -- Use `git commit -s` (DCO: `Signed-off-by`). +- **US English spelling** -- Enforced by `misspell -locale US` in CI. +- **Interface-driven design** -- JetStream and micro packages define interfaces (`JetStream`, `Stream`, `Consumer`, `Service`) with concrete unexported implementations. + +## Key Types + +- `nats.Conn` -- Core connection, handles all NATS protocol operations. +- `nats.Msg` -- Message type for pub/sub and request/reply. +- `nats.Subscription` -- Represents a subscription (sync, async, or channel-based). +- `jetstream.JetStream` -- Entry point for new JetStream API (created via `jetstream.New(nc)`). +- `jetstream.Stream`, `jetstream.Consumer` -- Stream and consumer management. +- `micro.Service` -- Micro service instance (created via `micro.AddService(nc, config)`). diff --git a/vendor/github.com/nats-io/nats.go/README.md b/vendor/github.com/nats-io/nats.go/README.md index 566a796eec..c3f40084ce 100644 --- a/vendor/github.com/nats-io/nats.go/README.md +++ b/vendor/github.com/nats-io/nats.go/README.md @@ -23,7 +23,7 @@ A [Go](http://golang.org) client for the [NATS messaging system](https://nats.io go get github.com/nats-io/nats.go@latest # To get a specific version: -go get github.com/nats-io/nats.go@v1.49.0 +go get github.com/nats-io/nats.go@v1.50.0 # Note that the latest major version for NATS Server is v2: go get github.com/nats-io/nats-server/v2@latest diff --git a/vendor/github.com/nats-io/nats.go/go_test.mod b/vendor/github.com/nats-io/nats.go/go_test.mod index 6bed135a81..80e6c7daf0 100644 --- a/vendor/github.com/nats-io/nats.go/go_test.mod +++ b/vendor/github.com/nats-io/nats.go/go_test.mod @@ -1,22 +1,22 @@ module github.com/nats-io/nats.go -go 1.24.0 +go 1.25.0 require ( - github.com/golang/protobuf v1.4.2 - github.com/klauspost/compress v1.18.2 - github.com/nats-io/jwt/v2 v2.8.0 - github.com/nats-io/nats-server/v2 v2.12.3 - github.com/nats-io/nkeys v0.4.12 + github.com/golang/protobuf v1.5.4 + github.com/klauspost/compress v1.18.5 + github.com/nats-io/jwt/v2 v2.8.1 + github.com/nats-io/nats-server/v2 v2.12.6 + github.com/nats-io/nkeys v0.4.15 github.com/nats-io/nuid v1.0.1 - google.golang.org/protobuf v1.23.0 + google.golang.org/protobuf v1.33.0 ) require ( - github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op // indirect - github.com/google/go-tpm v0.9.7 // indirect + github.com/antithesishq/antithesis-sdk-go v0.6.0-default-no-op // indirect + github.com/google/go-tpm v0.9.8 // indirect github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 // indirect - golang.org/x/crypto v0.46.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/time v0.14.0 // indirect + golang.org/x/crypto v0.49.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/time v0.15.0 // indirect ) diff --git a/vendor/github.com/nats-io/nats.go/go_test.sum b/vendor/github.com/nats-io/nats.go/go_test.sum index beb0dffe89..10127110d4 100644 --- a/vendor/github.com/nats-io/nats.go/go_test.sum +++ b/vendor/github.com/nats-io/nats.go/go_test.sum @@ -1,5 +1,5 @@ -github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op h1:Ucf+QxEKMbPogRO5guBNe5cgd9uZgfoJLOYs8WWhtjM= -github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= +github.com/antithesishq/antithesis-sdk-go v0.6.0-default-no-op h1:kpBdlEPbRvff0mDD1gk7o9BhI16b9p5yYAXRlidpqJE= +github.com/antithesishq/antithesis-sdk-go v0.6.0-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -7,32 +7,34 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= -github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= -github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= -github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= +github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= +github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 h1:KGuD/pM2JpL9FAYvBrnBBeENKZNh6eNtjqytV6TYjnk= github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= -github.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g= -github.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA= -github.com/nats-io/nats-server/v2 v2.12.3 h1:KRv+1n7lddMVgkJPQer+pt36TcO0ENxjilBmeWdjcHs= -github.com/nats-io/nats-server/v2 v2.12.3/go.mod h1:MQXjG9WjyXKz9koWzUc3jYUMKD8x3CLmTNy91IQQz3Y= -github.com/nats-io/nkeys v0.4.12 h1:nssm7JKOG9/x4J8II47VWCL1Ds29avyiQDRn0ckMvDc= -github.com/nats-io/nkeys v0.4.12/go.mod h1:MT59A1HYcjIcyQDJStTfaOY6vhy9XTUjOFo+SVsvpBg= +github.com/nats-io/jwt/v2 v2.8.1 h1:V0xpGuD/N8Mi+fQNDynXohVvp7ZztevW5io8CUWlPmU= +github.com/nats-io/jwt/v2 v2.8.1/go.mod h1:nWnOEEiVMiKHQpnAy4eXlizVEtSfzacZ1Q43LIRavZg= +github.com/nats-io/nats-server/v2 v2.12.6 h1:Egbx9Vl7Ch8wTtpXPGqbehkZ+IncKqShUxvrt1+Enc8= +github.com/nats-io/nats-server/v2 v2.12.6/go.mod h1:4HPlrvtmSO3yd7KcElDNMx9kv5EBJBnJJzQPptXlheo= +github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= +github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= -golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -41,3 +43,5 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/vendor/github.com/nats-io/nats.go/jetstream/consumer.go b/vendor/github.com/nats-io/nats.go/jetstream/consumer.go index de3d131c6d..ee0c6f1f22 100644 --- a/vendor/github.com/nats-io/nats.go/jetstream/consumer.go +++ b/vendor/github.com/nats-io/nats.go/jetstream/consumer.go @@ -500,8 +500,8 @@ func validateConsumerName(name string) error { if name == "" { return fmt.Errorf("%w: name is required", ErrInvalidConsumerName) } - if strings.ContainsAny(name, ">*. /\\") { - return fmt.Errorf("%w: '%s'", ErrInvalidConsumerName, name) + if strings.ContainsAny(name, ">*. /\\\t\r\n") { + return fmt.Errorf("%w: %q", ErrInvalidConsumerName, name) } return nil } diff --git a/vendor/github.com/nats-io/nats.go/jetstream/jetstream.go b/vendor/github.com/nats-io/nats.go/jetstream/jetstream.go index 57f555c794..e2c15ac636 100644 --- a/vendor/github.com/nats-io/nats.go/jetstream/jetstream.go +++ b/vendor/github.com/nats-io/nats.go/jetstream/jetstream.go @@ -316,6 +316,22 @@ type ( // MaxConsumers is the maximum number of consumers allowed for this // account. MaxConsumers int `json:"max_consumers"` + + // MaxAckPending is the maximum number of outstanding ACKs any consumer + // may configure. + MaxAckPending int `json:"max_ack_pending"` + + // MemoryMaxStreamBytes is is the maximum size any single memory based + // stream may be. + MemoryMaxStreamBytes int64 `json:"memory_max_stream_bytes"` + + // StoreMaxStreamBytes is the maximum size any single storage based + // stream may be. + StoreMaxStreamBytes int64 `json:"storage_max_stream_bytes"` + + // MaxBytesRequired indicates if max bytes is required to be set for + // streams in this account. + MaxBytesRequired bool `json:"max_bytes_required"` } jetStream struct { @@ -966,8 +982,8 @@ func validateStreamName(stream string) error { if stream == "" { return ErrStreamNameRequired } - if strings.ContainsAny(stream, ">*. /\\") { - return fmt.Errorf("%w: '%s'", ErrInvalidStreamName, stream) + if strings.ContainsAny(stream, ">*. /\\\t\r\n") { + return fmt.Errorf("%w: %q", ErrInvalidStreamName, stream) } return nil } diff --git a/vendor/github.com/nats-io/nats.go/jetstream/kv.go b/vendor/github.com/nats-io/nats.go/jetstream/kv.go index 8e1310918d..c58177be8b 100644 --- a/vendor/github.com/nats-io/nats.go/jetstream/kv.go +++ b/vendor/github.com/nats-io/nats.go/jetstream/kv.go @@ -19,6 +19,7 @@ import ( "fmt" "reflect" "regexp" + "slices" "strconv" "strings" "sync" @@ -170,15 +171,20 @@ type ( // argument. It can be configured with the same options as Watch. WatchFiltered(ctx context.Context, keys []string, opts ...WatchOpt) (KeyWatcher, error) - // Keys will return all keys. - // Deprecated: Use ListKeys instead to avoid memory issues. + // Keys will return all keys, filtering out any duplicates. + // For large datasets, this can be memory-heavy as all keys are loaded + // into memory. Use ListKeys for a streaming alternative. Keys(ctx context.Context, opts ...WatchOpt) ([]string, error) // ListKeys will return KeyLister, allowing to retrieve all keys from // the key value store in a streaming fashion (on a channel). + // Note: On buckets with a large number of keys and frequent writes, + // duplicate keys may be reported during listing. ListKeys(ctx context.Context, opts ...WatchOpt) (KeyLister, error) // ListKeysFiltered returns a KeyLister for filtered keys in the bucket. + // Note: On buckets with a large number of keys and frequent writes, + // duplicate keys may be reported during listing. ListKeysFiltered(ctx context.Context, filters ...string) (KeyLister, error) // History will return all historical values for the key (up to @@ -1363,7 +1369,7 @@ func (kv *kvs) WatchAll(ctx context.Context, opts ...WatchOpt) (KeyWatcher, erro return kv.Watch(ctx, AllKeys, opts...) } -// Keys will return all keys. +// Keys will return all keys, filtering out any duplicates. func (kv *kvs) Keys(ctx context.Context, opts ...WatchOpt) ([]string, error) { opts = append(opts, IgnoreDeletes(), MetaOnly()) watcher, err := kv.WatchAll(ctx, opts...) @@ -1382,7 +1388,8 @@ func (kv *kvs) Keys(ctx context.Context, opts ...WatchOpt) ([]string, error) { if len(keys) == 0 { return nil, ErrNoKeysFound } - return keys, nil + slices.Sort(keys) + return slices.Compact(keys), nil } type keyLister struct { @@ -1391,6 +1398,8 @@ type keyLister struct { } // ListKeys will return all keys. +// Note: On buckets with a large number of keys and frequent writes, +// duplicate keys may be reported during listing. func (kv *kvs) ListKeys(ctx context.Context, opts ...WatchOpt) (KeyLister, error) { opts = append(opts, IgnoreDeletes(), MetaOnly()) watcher, err := kv.WatchAll(ctx, opts...) @@ -1418,6 +1427,8 @@ func (kv *kvs) ListKeys(ctx context.Context, opts ...WatchOpt) (KeyLister, error } // ListKeysFiltered returns a KeyLister for filtered keys in the bucket. +// Note: On buckets with a large number of keys and frequent writes, +// duplicate keys may be reported during listing. func (kv *kvs) ListKeysFiltered(ctx context.Context, filters ...string) (KeyLister, error) { watcher, err := kv.WatchFiltered(ctx, filters, IgnoreDeletes(), MetaOnly()) if err != nil { diff --git a/vendor/github.com/nats-io/nats.go/jetstream/ordered.go b/vendor/github.com/nats-io/nats.go/jetstream/ordered.go index 4d10c29c8c..1e89a4de8c 100644 --- a/vendor/github.com/nats-io/nats.go/jetstream/ordered.go +++ b/vendor/github.com/nats-io/nats.go/jetstream/ordered.go @@ -116,22 +116,28 @@ func (c *orderedConsumer) Consume(handler MessageHandler, opts ...PullConsumeOpt c.subscription = sub internalHandler := func(serial int) func(msg Msg) { return func(msg Msg) { + c.Lock() // handler is a noop if message was delivered for a consumer with different serial if serial != c.serial { + c.Unlock() return } meta, err := msg.Metadata() if err != nil { - c.errHandler(serial)(c.currentSub, err) + currentSub := c.currentSub + c.Unlock() + c.errHandler(serial)(currentSub, err) return } dseq := meta.Sequence.Consumer if dseq != c.cursor.deliverSeq+1 { + c.Unlock() c.errHandler(serial)(sub, errOrderedSequenceMismatch) return } c.cursor.deliverSeq = dseq c.cursor.streamSeq = meta.Sequence.Stream + c.Unlock() handler(msg) } } @@ -371,10 +377,10 @@ func (s *orderedSubscription) Drain() { if !s.closed.CompareAndSwap(0, 1) { return } + s.consumer.Lock() + defer s.consumer.Unlock() if s.consumer.currentSub != nil { - s.consumer.currentConsumer.Lock() s.consumer.currentSub.Drain() - s.consumer.currentConsumer.Unlock() } close(s.done) } diff --git a/vendor/github.com/nats-io/nats.go/jetstream/pull.go b/vendor/github.com/nats-io/nats.go/jetstream/pull.go index b65c012502..571b7c7d8b 100644 --- a/vendor/github.com/nats-io/nats.go/jetstream/pull.go +++ b/vendor/github.com/nats-io/nats.go/jetstream/pull.go @@ -1085,6 +1085,10 @@ func (s *pullSubscription) cleanup() { if s.subscription == nil || !s.subscription.IsValid() { return } + if s.consumer != nil { + nc := s.consumer.js.conn + nc.RemoveStatusListener(s.connStatusChanged) + } if s.hbMonitor != nil { s.hbMonitor.Stop() } diff --git a/vendor/github.com/nats-io/nats.go/jsm.go b/vendor/github.com/nats-io/nats.go/jsm.go index eaa2f632b9..5f66e1d809 100644 --- a/vendor/github.com/nats-io/nats.go/jsm.go +++ b/vendor/github.com/nats-io/nats.go/jsm.go @@ -367,8 +367,10 @@ type Tier struct { // APIStats reports on API calls to JetStream for this account. type APIStats struct { - Total uint64 `json:"total"` - Errors uint64 `json:"errors"` + Level int `json:"level"` + Total uint64 `json:"total"` + Errors uint64 `json:"errors"` + Inflight uint64 `json:"inflight,omitempty"` } // AccountLimits includes the JetStream limits of the current account. diff --git a/vendor/github.com/nats-io/nats.go/kv.go b/vendor/github.com/nats-io/nats.go/kv.go index 6459e7602f..dd24c3d3c7 100644 --- a/vendor/github.com/nats-io/nats.go/kv.go +++ b/vendor/github.com/nats-io/nats.go/kv.go @@ -19,6 +19,7 @@ import ( "fmt" "reflect" "regexp" + "slices" "strconv" "strings" "sync" @@ -68,10 +69,13 @@ type KeyValue interface { // WatchFiltered will watch for any updates to keys that match the keys // argument. It can be configured with the same options as Watch. WatchFiltered(keys []string, opts ...WatchOpt) (KeyWatcher, error) - // Keys will return all keys. - // Deprecated: Use ListKeys instead to avoid memory issues. + // Keys will return all keys, filtering out any duplicates. + // For large datasets, this can be memory-heavy as all keys are loaded + // into memory. Use ListKeys for a streaming alternative. Keys(opts ...WatchOpt) ([]string, error) // ListKeys will return all keys in a channel. + // Note: On buckets with a large number of keys and frequent writes, + // duplicate keys may be reported during listing. ListKeys(opts ...WatchOpt) (KeyLister, error) // History will return all historical values for the key. History(key string, opts ...WatchOpt) ([]KeyValueEntry, error) @@ -867,7 +871,7 @@ func (kv *kvs) PurgeDeletes(opts ...PurgeOpt) error { return nil } -// Keys() will return all keys. +// Keys will return all keys, filtering out any duplicates. func (kv *kvs) Keys(opts ...WatchOpt) ([]string, error) { opts = append(opts, IgnoreDeletes(), MetaOnly()) watcher, err := kv.WatchAll(opts...) @@ -886,7 +890,8 @@ func (kv *kvs) Keys(opts ...WatchOpt) ([]string, error) { if len(keys) == 0 { return nil, ErrNoKeysFound } - return keys, nil + slices.Sort(keys) + return slices.Compact(keys), nil } type keyLister struct { @@ -895,6 +900,8 @@ type keyLister struct { } // ListKeys will return all keys. +// Note: On buckets with a large number of keys and frequent writes, +// duplicate keys may be reported during listing. func (kv *kvs) ListKeys(opts ...WatchOpt) (KeyLister, error) { opts = append(opts, IgnoreDeletes(), MetaOnly()) watcher, err := kv.WatchAll(opts...) diff --git a/vendor/github.com/nats-io/nats.go/nats.go b/vendor/github.com/nats-io/nats.go/nats.go index 56ad8c6c99..122b88b2dd 100644 --- a/vendor/github.com/nats-io/nats.go/nats.go +++ b/vendor/github.com/nats-io/nats.go/nats.go @@ -1,4 +1,4 @@ -// Copyright 2012-2024 The NATS Authors +// Copyright 2012-2026 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 @@ -38,6 +38,7 @@ import ( "strings" "sync" "sync/atomic" + "syscall" "time" "github.com/nats-io/nkeys" @@ -48,7 +49,7 @@ import ( // Default Constants const ( - Version = "1.49.0" + Version = "1.50.0" DefaultURL = "nats://127.0.0.1:4222" DefaultPort = 4222 DefaultMaxReconnect = 60 @@ -150,6 +151,7 @@ var ( ErrMaxConnectionsExceeded = errors.New("nats: server maximum connections exceeded") ErrMaxAccountConnectionsExceeded = errors.New("nats: maximum account active connections exceeded") ErrConnectionNotTLS = errors.New("nats: connection is not tls") + ErrTLS = errors.New("nats: tls error") ErrMaxSubscriptionsExceeded = errors.New("nats: server maximum subscriptions exceeded") ErrWebSocketHeadersAlreadySet = errors.New("nats: websocket connection headers already set") ErrServerNotInPool = errors.New("nats: selected server is not in the pool") @@ -2342,7 +2344,7 @@ func (nc *Conn) makeTLSConn() error { nc.conn = tls.Client(nc.conn, tlsCopy) conn := nc.conn.(*tls.Conn) if err := conn.Handshake(); err != nil { - return err + return fmt.Errorf("%w: %w", ErrTLS, err) } nc.bindToNewConn() return nil @@ -2585,6 +2587,31 @@ func (nc *Conn) setup() { copy(pub, _HPUB_P_) } +// tlsHandshakeEOF wraps an error with context when it occurs right after +// a completed TLS handshake, which typically indicates the remote side +// rejected the client certificate (e.g. an mTLS proxy like nginx). +// Depending on timing, the error may be io.EOF (read from closed conn) +// or a "broken pipe"/"connection reset" (write to closed conn). +func (nc *Conn) tlsHandshakeEOF(err error) error { + tlsConn, ok := nc.conn.(*tls.Conn) + if !ok || !tlsConn.ConnectionState().HandshakeComplete { + return err + } + if errors.Is(err, io.EOF) || isConnClosedError(err) { + return fmt.Errorf("%w: connection closed by remote after TLS handshake: %w", ErrTLS, err) + } + return err +} + +// isConnClosedError reports whether the error indicates the remote +// side closed the connection (broken pipe or connection reset). +// NOTE: On Windows, connection resets use WSAECONNRESET which may not +// match syscall.ECONNRESET. In that case, the error will not be +// detected here but will still be returned unwrapped by the caller. +func isConnClosedError(err error) bool { + return errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ECONNRESET) +} + // Process a connected connection and initialize properly. func (nc *Conn) processConnectInit() error { // Set our deadline for the whole connect process @@ -2605,14 +2632,14 @@ func (nc *Conn) processConnectInit() error { // Process the INFO protocol received from the server err := nc.processExpectedInfo() if err != nil { - return err + return nc.tlsHandshakeEOF(err) } // Send the CONNECT protocol along with the initial PING protocol. // Wait for the PONG response (or any error that we get from the server). err = nc.sendConnect() if err != nil { - return err + return nc.tlsHandshakeEOF(err) } // Reset the number of PING sent out diff --git a/vendor/github.com/nats-io/nats.go/ws.go b/vendor/github.com/nats-io/nats.go/ws.go index 3642917939..8d420e8257 100644 --- a/vendor/github.com/nats-io/nats.go/ws.go +++ b/vendor/github.com/nats-io/nats.go/ws.go @@ -85,6 +85,7 @@ type websocketReader struct { nl bool dc *wsDecompressor nc *Conn + closeErr error } type wsDecompressor struct { @@ -202,6 +203,15 @@ func (r *websocketReader) Read(p []byte) (int, error) { return r.drainPending(p), nil } + // If we have a deferred close error (from a previous Read that + // had both data frames and a close frame), return it now that + // pending data has been drained. + if r.closeErr != nil { + err := r.closeErr + r.closeErr = nil + return 0, err + } + // Get some data from the underlying reader. n, err := r.r.Read(p) if err != nil { @@ -285,6 +295,13 @@ func (r *websocketReader) Read(p []byte) (int, error) { if wsIsControlFrame(frameType) { pos, err = r.handleControlFrame(frameType, buf, pos, rem) if err != nil { + // If we already have pending data (e.g. a -ERR message + // that arrived before this close frame), defer the error + // so the pending data can be returned to the caller first. + if len(r.pending) > 0 { + r.closeErr = err + break + } return 0, err } rem = 0 diff --git a/vendor/modules.txt b/vendor/modules.txt index 847b0d4e9e..c20ce6049f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -880,8 +880,8 @@ github.com/justinas/alice # github.com/kevinburke/ssh_config v1.2.0 ## explicit github.com/kevinburke/ssh_config -# github.com/klauspost/compress v1.18.4 -## explicit; go 1.23 +# github.com/klauspost/compress v1.18.5 +## explicit; go 1.24 github.com/klauspost/compress github.com/klauspost/compress/flate github.com/klauspost/compress/fse @@ -1177,8 +1177,8 @@ github.com/nats-io/nats-server/v2/server/stree github.com/nats-io/nats-server/v2/server/sysmem github.com/nats-io/nats-server/v2/server/thw github.com/nats-io/nats-server/v2/server/tpm -# github.com/nats-io/nats.go v1.49.0 -## explicit; go 1.24.0 +# github.com/nats-io/nats.go v1.50.0 +## explicit; go 1.25.0 github.com/nats-io/nats.go github.com/nats-io/nats.go/encoders/builtin github.com/nats-io/nats.go/internal/parser