Releases: tecnickcom/nurago
Release list
v1.147.1
test: cover empty select branches reported as uncovered by Coveralls
Add tests exercising the two branches:
- httpserver: the default branch of the non-blocking serve failure publish, taken when the serveErr buffer is already full
- valkey: the subscription context Done branch in the delivery callback, taken when Close tears down the subscription while a message is blocked waiting for a consumer
Full Changelog: v1.147.0...v1.147.1
v1.147.0
Remove deprecated APIs
BREAKING CHANGE: the deprecated encode.JsonEncoder function, typeutil.Pointer function, and the NameErrorLevel constants in metrics/opentel and metrics/prometheus have been removed; use encode.JSONEncoder, new(), and NameLogLevel instead.
Full Changelog: v1.146.0...v1.147.0
v1.146.0
feat!: rename module from gogen to nurago
Complete the rename started with the GitHub repository rename and the v1.145.0 deprecation release: the module path is now github.com/tecnickcom/nurago.
BREAKING CHANGE: importers must replace github.com/tecnickcom/gogen with github.com/tecnickcom/nurago in their import paths. The old module path remains frozen at v1.145.0 with a deprecation notice.
Full Changelog: v1.145.0...v1.146.0
v1.145.0
gogen has been renamed to nurago — final release under this module path
This is the last release of github.com/tecnickcom/gogen. The project continues, unchanged and actively maintained, as github.com/tecnickcom/nurago: same library, same packages, same maintainer, new name.
This release contains no functional changes. It only adds the Go module deprecation notice to go.mod and a rename banner to the README, so that go get, go list -m -u, and pkg.go.dev inform users of the new import path.
To migrate, update your imports and dependencies:
go get github.com/tecnickcom/nurago@latest
find . -name '*.go' -exec sed -i 's|github.com/tecnickcom/gogen|github.com/tecnickcom/nurago|g' {} +
go mod tidy
Nothing breaks if you stay: every published gogen version remains permanently available via the Go module proxy. However, all future development, fixes, and releases happen only under nurago.
Why "nurago"? From nuraghe + Go: the Bronze Age Sardinian stone towers, built from dry-laid stone without mortar, thousands of which still stand after 3,500 years — modular, stone-solid foundations with no lock-in, which is exactly what this library aims to be.
Full Changelog: v1.144.0...v1.145.0
v1.144.0
✨ Features
pkg/passwordhash: PHC string format support
Optional support for the cross-language PHC string format ($argon2id$v=19$m=...,t=...,p=...$salt$key) alongside the default self-describing base64-JSON format. This enables password-hash interoperability with other ecosystems — PHP password_hash, Python argon2-cffi/passlib, and the Argon2 reference CLI — without bulk re-hashing.
WithFormat(f, accept...)selects the serialization emitted byPasswordHashand the set of formatsPasswordNeedsRehashtreats as current. The default remains base64 JSON, so existing deployments are unaffected.- Auto-detected verification:
PasswordVerifyandPasswordNeedsRehashdetect each stored value's format from its leading$, so both formats can coexist in one store, switching formats never invalidates a credential, and externally mintedargon2idPHC hashes verify with no configuration change. - Format-aware rehash migration:
PasswordNeedsRehashflags hashes stored in a non-accepted format as needing a rehash even when their Argon2 parameters are current, so a store converges to the configured format through the ordinary rehash-on-login flow. Listing both formats viaacceptkeeps a deliberately mixed store; verification is never restricted by this option. - Safe by default: unknown emit values normalize to
FormatJSONand unknown accept values are ignored (never aliased), so misconfiguration can neither select an unsupported serialization nor silently widen the accepted set. Pepper-encrypted methods are unaffected. - Strict, secure PHC parsing: deserialized parameters flow through the same bounds validation as the JSON format; only
argon2idat version 19 with cost parameters inm,t,porder is accepted; optionalkeyid/dataattributes and padded base64 are rejected; newline characters and non-canonical base64 trailing bits are rejected so byte-distinct strings can never decode to the same salt/key; and$/comma splits are capped so adversarial inputs cannot allocate large slices before rejection.
Tests pin the wire format with a frozen PHC reference, cross-implementation interop against a vector minted by PHP's password_hash(PASSWORD_ARGON2ID), cross-format verifiability, convergence/mixed-store semantics, and 15 malformed-PHC rejection cases. Fuzz seeds cover the PHC decode path, plus a new benchmark for PHC verification against the JSON baseline. Coverage remains 100% with a clean strict lint run.
🔧 Maintenance
- Updated dependencies
Full Changelog: v1.143.0...v1.144.0
v1.143.0
This release reworks pkg/filter for a ~4x evaluation speedup and secure-by-default input limits, with a smaller public API. It also refactors the example service startup wiring. It contains breaking changes in pkg/filter.
⚠️ Breaking changes (pkg/filter)
- The package-level
ParseJSONfunction, theEvaluatorinterface, and theRule.Evaluatemethod are no longer exported.Ruleis now a pure data struct, and untrusted input must be decoded via the size-limited entry pointsProcessor.ParseJSONorProcessor.ParseURLQuery. - New secure-by-default limits reject previously-accepted oversized inputs unless raised via the matching options: rule string/regexp values are capped at 4096 bytes (
WithMaxValueLength), JSON payloads at 64 KiB (WithMaxFilterBytes), and field-selector nesting at depth 32 (WithMaxFieldDepth). The number of OR groups in a rule set is also capped. - A
nilinterface slice element combined with a field selector is now filtered out (non-match), consistent with nil-pointer handling, instead of returning an error.
Performance
- Rules are evaluated on a
reflect.Valueinstead of boxing every element and field into anany, and each rule's field path is resolved once perApplyfor concrete slices instead of a per-element cache lookup. TheEqual_10000benchmark drops from ~1.85 ms to ~0.44 ms (~4x), and per-element allocations drop from ~2 per element to a small constant.
Security
- All client-attributable errors are wrapped in the new
ErrInvalidFiltersentinel, so handlers can reject bad filters generically (e.g. HTTP 400) without surfacing client input or internal type names. - Added a package
Securitysection documenting RE2's linear-time matching (no ReDoS) and the caller's authorization responsibility, plus aFuzzFilterApplypanic-safety fuzz harness.
Examples
examples/service: decomposed the startup wiring into focused helpers (newIpifyClient,bindServiceHandlers,newDatabases,newLogConfig), removing thegocognit/funlen/nestif/prealloclint suppressions while keeping a linear, copy-paste-friendly startup blueprint.- The configured service logger is now threaded into
healthcheck.NewHandlerviaWithLogger, so health-check warnings and recovered panics are structured and release-correlated like every other component. - Shared outbound HTTP client options are built once and reused per client; the ipify client is documented as a diagnostic-only dependency deliberately not registered as a health check.
- Aligned the shipped config default
db.{main,read}.conn_max_openwithSetDefaultsand the JSON schema (50), and added a "service enabled, database disabled" bind test restoring 100% statement coverage.
All packages retain 100% test coverage and pass strict golangci-lint.
Full Changelog: v1.142.1...v1.143.0
v1.142.1
What's Changed
This release hardens the AWS packages (awsopt, awssecretcache, sqs, s3) around a single set of conventions: exported sentinel errors matchable with errors.Is, response/input guards that return errors instead of panicking, skipping AWS config load when a client is injected, and expanded docs with runnable examples.
⚠️ This release contains breaking changes in every package below. See the Breaking changes section before upgrading.
awsopt — partition-agnostic region extraction
- Reworked
WithRegionFromURLto extract the region as the right-most region-shaped host label instead of anchoring on.amazonaws.com, so standard, dual-stack (api.aws), China (amazonaws.com.cn), GovCloud, ISO (c2s.ic.gov,sc2s.sgov.gov), VPC interface endpoints, and future partitions all resolve with no code changes. - Endpoint URLs are now parsed with
net/url(host only; scheme optional; userinfo, port, and path ignored; case-insensitive), replacing the endpoint-extraction regexp with a small region-shape check. - Candidate labels are validated against the AWS region shape, so a service name or the
vpcelabel never becomes a bogus region. - Fixed VPC interface endpoint region resolution and scheme-less endpoints whose path/query contains
://. - Documented that
Optionsmust be built from a single goroutine, then shared read-only.
awssecretcache — sentinel errors and nil/empty-secret guards
- Added exported sentinel errors
ErrEmptySecretandErrEmptySecretID(wrapped with%w). - Guarded against a nil
GetSecretValueOutputsoGetSecretData,GetSecretBinary, andGetSecretStringreturnErrEmptySecretinstead of panicking. - Skipped the AWS config load when a client is injected via
WithSecretsManagerClient. - Rejected an empty secret id up front with
ErrEmptySecretIDinstead of a guaranteed-failing upstream call. - Documented
%wwrapping (typed SDK errors stay matchable viaerrors.As; context/abort errors viaerrors.Is), edge behavior onNew, and added a runnable Example.
sqs — sentinel errors, nil-response guards, client injection, URL-derived region
- Added exported sentinel errors (
ErrInvalidQueueURL,ErrMissingMessageGroupID,ErrUnexpectedMessageGroupID,ErrDedupIDNotAllowed,ErrInvalidDedupID,ErrNilEncodeFunc,ErrNilDecodeFunc,ErrInvalidWaitTime,ErrInvalidVisibilityTimeout,ErrQueueNotResponding). - Added
WithSQSClientto inject a custom implementation, skipping AWS config load when set. - Derived the AWS region from the queue URL via
awsopt.WithRegionFromURLwhen no explicit region is set (an explicitWithAWSOptionsregion still wins). - Validated the queue URL and FIFO message-group constraints before loading AWS config, so misconfiguration fails fast.
- Guarded against nil
ReceiveMessage/GetQueueAttributesoutput inReceiveandHealthCheck. - Wrapped encode/decode errors with
%w, documented concurrency safety, and added a runnable Example.
s3 — sentinel errors, nil-response guards, client injection, health check, object metadata
- Added exported sentinel errors (
ErrEmptyBucketName,ErrEmptyKey,ErrEmptyObjectBody,ErrBucketNotResponding). - Added
WithS3Clientto inject a custom implementation, skipping AWS config load when set. - Added
HealthCheck, probing bucket reachability and access viaHeadBucket(requiress3:ListBucket). - Exposed object metadata on
Object(ContentType,ContentLength,ETag,LastModified, plusBucketandKey). - Added
ListObjectsreturning per-object metadata (ObjectInfowithKey,Size,LastModified,ETag);ListKeysis now a thin projection over it sharing a single pagination path. - Defaulted a nil
Putreader tohttp.NoBody, validated bucket/key before calling AWS, and stopped pagination when the continuation token does not advance (prevents an infinite loop against non-conformant endpoints). - Guarded against nil
GetObject/ListObjectsV2output, documented concurrency safety, and added a runnable Example.
Maintenance
- Updated dependencies and bumped version.
⚠️ Breaking changes
awsopt
- When the URL carries no region and no
defaultRegionis given,WithRegionFromURLnow adds no region option and defers to the SDK's canonical resolution (AWS_REGION, thenAWS_DEFAULT_REGION, then the shared config file, then IMDS) instead of substituting a hardcodedus-east-2default. - Region resolution no longer requires an
amazonaws.comhost: any host carrying a region-shaped label yields that region, so the host is no longer verified to be AWS-owned.
awssecretcache
GetSecretBinaryandGetSecretStringnow returnErrEmptySecretwhen the response holds no value, instead of an empty value with a nil error (an explicitly empty""/[]byteis still returned as a real value).GetSecretData,GetSecretBinary, andGetSecretStringnow returnErrEmptySecretIDfor an empty key instead of attempting an upstream lookup.
sqs
Newnow returnsErrUnexpectedMessageGroupIDwhen a message group ID is supplied for a standard (non-FIFO) queue instead of silently ignoring it.Newnow validates the queue URL and returnsErrInvalidQueueURLfor an empty or malformed URL instead of failing only on first use.- The region is now derived from the queue URL and takes precedence over the
AWS_REGIONenvironment variable (an explicitWithAWSOptionsregion still wins). - Package errors are now exported sentinel values and several error message texts changed.
s3
- The
S3interface gains aHeadBucketmethod; existing implementations (including test mocks) must provide it. Newnow returnsErrEmptyBucketNamefor an empty bucket name instead of failing only on first use.Get,Put, andDeletenow returnErrEmptyKeyfor an empty key instead of issuing an AWS request.- Package errors are now exported sentinel values, and the wrapped list error text changed from
"cannot list s3 keys"to"cannot list s3 objects".
Full Changelog: v1.141.0...v1.142.1
v1.141.0
v1.141.0
This release makes gogen fully pure-Go, removes the go.uber.org/multierr dependency, and applies a consistent hardening pass across the HTTP-client, messaging, and country-data packages: exported sentinel errors matchable with errors.Is, construction-time validation instead of deferred or panicking failures, bounded/secret-safe response handling, and client injection for dependency-free unit tests.
⚠️ This is a breaking release. Every package below marked with!changes behavior, option names, or error types. See Breaking changes for migration notes.
Highlights
- gogen is now 100% pure-Go. The only CGO dependency,
pkg/kafkacgo(Confluent/librdkafka), has been removed — cross-compilation, scratch/distroless images, and CGO-free builds now work out of the box. go.uber.org/multierrdependency dropped.kafka,validator, anderrutilnow use the standard library'serrors.Join, so the module no longer depends on multierr.- Uniform error taxonomy. HTTP clients (
devlake,jirasrv,slack,sleuth,ipify) and messaging clients (kafka,redis,valkey) now export sentinel errors wrapped with%w, so callers can distinguish configuration problems from response/runtime failures viaerrors.Is. - Fail fast at construction. Retry/option validation moved from the first request/send into
New/NewProducer/NewConsumer. - Safer responses. Response bodies are drained and capped with
io.LimitReaderfor connection reuse, non-2xx snippets (secret-redacted) are appended to errors, and nil-request/nil-body guards replace latent panics.
Breaking changes
pkg/kafkacgoremoved. Migrate togithub.com/tecnickcom/gogen/pkg/kafka(context-native, no CGO); note the option/error surface differs (segmentio/kafka-go rather than librdkafka).kafka:NewProducer/NewConsumervalidate at construction and return errors matchingErrInvalidOptions/ErrNilEncodeFunc/ErrNilDecodeFunc;NewProducer'surlsparameter renamed tobrokers;Receive/FetchMessage/ReceiveDatareturnErrConsumerClosedafterClose(no longer wrapio.EOF).redis:Get/GetDatareturnErrKeyNotFound(no longer matchesredis.Nil);WithSubscrChannels→WithChannels,WithSubscrChannelOptions→WithChannelOptions; empty channel names andAddr/Networkmismatches rejected at construction.valkey: subscription lifetime is bound toCloserather than theNewcontext (Closeis now mandatory when channels are configured);Get/GetDatareturnErrKeyNotFound(no longer matchesvalkeygo.Nil/IsValkeyNil); empty channel names rejected.ipify: a 200 with an empty body now returnsErrInvalidResponse, non-http/httpsURLs are rejected at construction, and the response body is capped at 64 bytes.devlake/jirasrv/sleuth:Newvalidates retry options (ErrInvalidRetryConfig) at construction; retries now honor a server-providedRetry-After(capped at 60s); error message texts changed.slack:HealthChecknow fails during an active Apps/Integrations/APIs incident (previously it could never fail); default ping URL changed tohttps://slack-status.com; retry validation moved to construction.countryphone:NumInfo.Geochanges from[]*GeoInfoto[]GeoInfo; removed the unusedPrefixDataalias; dropped non-ISO codesCT(+90) andQN(+374) so+90→TRand+374→AMonly.countrycode: internal length/character/parse errors now wrap the exportedErrInvalidCode/ErrNotFound.validator: the aggregate error fromValidateStruct/ValidateStructCtxnow renders with newline separators (errors.Join) instead of multierr's"; ". The error type,errors.Is/errors.Astraversal, and one-*Error-per-failed-tag structure are unchanged; only the concatenatedError()string differs.
Changes by package
kafka
- Sentinel errors
ErrInvalidOptions,ErrNilEncodeFunc,ErrNilDecodeFunc,ErrConsumerClosed. WithKafkaReader/WithKafkaWriterinject an existing kafka-go reader/writer (via newKReader/KWriterinterfaces) for dependency-free tests.- Add
Producer.HealthCheckandWithBrokerCheckFunc(custom per-broker probe). - Replace
go.uber.org/multierrwith stdliberrors.Join; probe every broker and join errors only when all fail; clone the caller's broker slice at construction.
redis
- Sentinel errors incl.
ErrKeyNotFound,ErrNoSubscription,ErrSubscriptionClosed,ErrInvalidChannelName. - Unix domain socket support;
WithRedisClientinjection; idempotentClose. - Extensive doc and test rework (key-not-found, double
Close, concurrentClose, nil-message skipping, unix socket validation); coverage stays 100%.
valkey
- Sentinel errors mirroring
redis; deterministic clean-closure reporting via an atomic closed flag; idempotentCloseviasync.Once. - Skip
InitAddressvalidation when a client is injected viaWithValkeyClient.
ipify
- Export
ErrInvalidOptions/ErrInvalidResponse; URL validation at construction; nil-body guard; addClient.HealthCheck.
devlake / jirasrv / sleuth
- Sentinel errors, single prebuilt retrier (method-aware read/write retriers in
jirasrv),Retry-Aftersupport, bounded response drains, nil-request guards, and secret-safe error snippets.
slack
- Real status-incident health check against the live Slack status API v2.0.0, sentinel errors,
WithRetryDelay, and secret-safe address validation.
countryphone
- Value-slice
GeoInfo, sentinel errors (ErrNoMatch,ErrInvalidNumberType,ErrInvalidAreaType), nil-entry and empty-prefix guards, hoisted lookup tables, benchmarks, and runnable examples.
countrycode
- Exported
ErrInvalidCode/ErrNotFound; fixed custom-data field population and region/sub-region resolution by code; fuzz tests, benchmarks, and typo fixes.
validator / errutil
- Drop
go.uber.org/multierr:validatorbuilds its aggregate error viaerrors.Join; the per-failed-tag*Errorstructure, count, and order are unchanged. - Add
errutil.Errors, a dependency-free helper that enumerates the individual errors held in anerrors.Joinaggregate.
Maintenance
- Updated dependencies.
Full Changelog: v1.140.0...v1.141.0
v1.140.0
v1.140.0
Major security-focused reworks of the jwt, passwordhash, and passwordpwned packages. All three ship breaking API changes — see the Breaking Changes section before upgrading.
jwt — self-contained HMAC engine, verifier-based API, and security hardening
- Tokens are now signed and verified by a standard-library-only HMAC-SHA2 (HS256/HS384/HS512) implementation of the RFC 7515/7519 compact JWS, removing the
github.com/golang-jwt/jwt/v5build dependency (retained test-only for cross-validation). Restricting the surface to symmetric HMAC and verifying the signature before decoding claims makesalg=noneand algorithm-confusion attacks structurally impossible. - Pin the accepted signing algorithm and require
exp; validatenbfwith optional clock-skew leeway; enforceissand the fullaudset when configured. - Bound how long a session can be kept alive by renewals via an
auth_timeclaim preserved across renewals and a configurable maximum lifetime, so a stolen token cannot be renewed indefinitely. - Support HMAC key rotation through previous keys accepted for verification, validate minimum key length against the method hash size, and copy caller-supplied key material.
- Cap the login request body (413 on overflow) and reject unknown or trailing JSON; return generic client messages while logging details server-side; distinguish invalid credentials (401) from credential-backend failures (500).
- Emit RFC 6750
WWW-Authenticatechallenges on 401 responses and accept case-insensitive, multi-space Bearer prefixes per RFC 7235. - New API:
Authenticate,VerifyToken,IssueToken,MiddlewarewithClaimsFromContext, and optionsWithMaxBodyBytes,WithMaxSessionLifetime,WithClockSkewLeeway,WithPreviousKeys. - Fuzz tests for the login body and token parser, benchmarks for the issue and verify paths, and a runnable example; 100% statement coverage.
passwordhash — parameter envelope, rehash API, sentinel errors, and hardening
- Any hash the package can mint it can also verify: cost options clamp to the same [floor, ceiling] range the verification path accepts, and hashing rejects out-of-envelope configurations.
- Panics replaced with errors: invalid or zero-value
Paramsnow returnErrInvalidParamsinstead of panicking inside argon2. - Verification hardened against forged or corrupt blobs: encoded hashes larger than 16 KiB are rejected before decoding, deserialized parameters are validated against their bounds, and salt/key byte lengths are cross-checked against their declared sizes.
- New
PasswordNeedsRehashandEncryptPasswordNeedsRehashdetect hashes minted with outdated parameters, enabling transparent re-hashing on the next successful login. - Default parallelism is a flat 4 lanes (RFC 9106 §4) instead of
runtime.NumCPU(), so minted hashes are reproducible across heterogeneous hardware and a mixed fleet cannot enter a rehash loop; key and salt minimums for new hashes raised to 16 and 8 bytes. - Minimum-length policy is enforced only when hashing, not on verification, so raising the minimum no longer locks out existing users.
- Sentinel-error taxonomy matchable with
errors.Is:ErrPasswordTooShort,ErrPasswordTooLong,ErrInvalidParams,ErrInvalidHashData,ErrAlgoMismatch,ErrVersionMismatch,ErrInvalidPepperKey. - Derived keys and decrypted pepper material are wiped after comparison; fuzz, envelope round-trip, panic-safety, and boundary tests added; 100% coverage.
passwordpwned — breach-count API, hardened response validation, sentinel errors, and live health probe
- New
PwnedCountreturns the raw breach count for NIST-style threshold policies ("reject only if seen more than N times");IsPwnedPasswordis now a thin count>0 wrapper over it. - Decoded responses are capped at 8 MiB (configurable via
WithResponseSizeLimit) so a decompression bomb cannot exhaust memory, and are decoded according to their declaredContent-Encoding(brotli, gzip, identity) instead of assuming brotli. - Fail loud on garbage 200s: the body must begin with a structurally valid
<35-hex>:<count>range line, so a captive-portal page returnsErrMalformedResponseinstead of silently reading as "not pwned"; hash-suffix matching is case-insensitive, so lowercase-hex mirrors no longer produce silent false negatives. HealthCheckis now a live probe: a lightweight GET on a fixed range prefix bounded by a dedicated ping timeout (default 5 s,WithPingTimeout), never retried.- The HTTP retrier is built once in
New— invalid retry settings fail at construction — and a server-providedRetry-Afterheader is honored (capped at 60 s) on 429. - Sentinel-error taxonomy:
ErrInvalidURL,ErrInvalidUserAgent,ErrMalformedResponse,ErrResponseTooLarge,ErrUnsupportedEncoding,ErrUnexpectedStatus. - Tests pin the k-anonymity contract (only the 5-character hash prefix ever leaves the process), plus fuzz targets over the response parser and body reader; 100% coverage.
Other
- Fixed a flaky test timeout.
- Updated dependencies (including
golang.org/x/syncv0.22.0 andgolang.org/x/sysv0.47.0).
Breaking Changes
- jwt:
NewtakesVerifyCredentialsFn func(username, password string) (bool, error)instead ofUserHashFn— credential verification is fully delegated (pair it withpkg/passwordhash) and the package no longer performs bcrypt comparison itself.SigningMethodis now an HS256/HS384/HS512 enum,Claimscarries native fields instead of embeddingjwt.RegisteredClaims, andWithClaimSubjectis removed (thesubclaim is now the authenticated username). - passwordhash: default parallelism is a flat 4 instead of
runtime.NumCPU();WithKeyLen/WithSaltLenclamp to [16, 1024]/[8, 1024] andWithTime/WithMemorycap at 1024 passes/4 GiB (previously stored hashes remain verifiable unchanged).PasswordVerifyandEncryptPasswordVerifyno longer reject candidate passwords below the configured minimum length. InvalidParamsconfigurations that previously panicked now returnErrInvalidParams. - passwordpwned:
HealthChecknow performs a live request instead of always returning nil.Newrejects previously accepted configurations: URLs with a query or fragment, an empty or control-character User-Agent, zero retry attempts, and non-positive retry delays. A 200 response whose body is not valid HIBP range data now returnsErrMalformedResponseinstead of reporting the password as not pwned, andWithTimeoutignores non-positive values instead of disabling the client timeout.
Full Changelog: v1.139.0...v1.140.0
v1.139.0
v1.139.0
Broad hardening, performance, and API-ergonomics pass across the utility packages. Every touched package keeps 100% test coverage and a clean strict golangci-lint run, with new fuzz targets and benchmarks throughout.
✨ Features
- redact: Rework the redaction engine into a generic, allocation-free single-pass scanner for logs, HTTP dumps, JSON, XML, and form data. Adds detection for extra sensitive HTTP headers, URL userinfo passwords, JWT/JWE tokens, vendor credential literals (GitHub, GitLab, Slack, Stripe, AWS, Google, OpenAI/Anthropic, and more), and PEM private-key blocks; broadens credit-card detection to 13–19 digit PANs with grouped formats and a conservative Maestro policy; and guarantees convergent redaction backed by a permanent fuzz target. Introduces the canonical
String/Bytes/AppendTo/BytesToString/PooledAPI and a configurableRedactor(WithMarker,WithLuhnCheck,WithExtraTokens,WithoutTokens,WithoutRules), withHTTPData*retained as compatibility aliases. - dnscache: Add host normalization (case-fold + trailing-dot trim), IP-literal bypass, canonical de-duplication of resolved addresses, and RFC 6724-aware IPv4/IPv6 interleaving. Adds family-restricted network filtering,
errors.Joinfailure aggregation, sentinel errorsErrNoAddresses/ErrInvalidIP, and functional optionsWithDialer,WithDialTimeout,WithAddressRotation, andWithStaleIfError. - mysqllock: Add configurable keep-alive tuning (
WithKeepAliveInterval,WithKeepAlivePingTimeout,WithReleaseTimeout), explicit lock-loss signaling viaErrLockLostand per-acquisition/instanceWithLostLockHandler, and a robust idempotent release path. Fixes a deadlock when releasing from within a lock-loss handler, bounds keep-alive pings to detect hung connections, and adds sentinel errorsErrNilDB,ErrInvalidKey, andErrInvalidTimeout. - timeutil: Add sentinel errors
ErrInvalidDuration,ErrDurationOverflow, andErrParseDateTime; implementencoding.TextMarshaler/TextUnmarshaleronDurationandDateTime(usable as JSON map keys and with YAML/TOML/flag.TextVar); fix numeric overflow inDuration.UnmarshalJSON; and treat JSONnullas a no-op. - paging: Add
HasPreviousPage/HasNextPageflags (has_previous_page/has_next_page) so callers can toggle navigation links without re-deriving boundary conditions.
🐛 Fixes
- validator: Drop the custom
einoverride in favor of the upstream built-in, fill in missing error templates (bcp47_strict_language_tag,mimetype,noneof,noneofci,origin), parsefalseifnumeric params in base 10, and validate error templates at registration time. GuardsisE164NoPlus/isUSZIPCodeagainst non-string fields. - strsplit: Fix
ChunkLineemitting a blank chunk for whitespace-only input shorter than the size. RefactorsChunk/ChunkLineinto single-purpose helpers (output byte-for-byte identical), pre-sizes result slices, and clarifies byte-size semantics and boundary handling. - testutil: Bound
ReplaceDateTimeto the RFC3339 grammar andReplaceUnixTimestampto a word-bounded 19-digit match; fixCaptureOutputto restore the logger's real destination and close both pipe ends on every exit path (avoiding a goroutine/FD leak); tightenNewErrorCloser's exported surface to exactlyio.ReadCloser.
⚡ Performance
- random: Reduce allocations and speed up UUID/UID generation. UUIDv7 reads entropy into a stack buffer (~3% faster),
RandStringmaps accepted bytes in place (4→2 allocs, ~12% faster at n=16), andTUID128/TUID64gain zero-allocationFormat/Bytemethods (TUID128.Hex~36% faster,String3→1 allocs, ~28% faster). - uhex: Use a 256-entry lookup table for ~2–3× faster fixed-width hex encoding.
- stringkey: Single-pass field normalization (collapse whitespace + lowercase together) with
norm.NFC.Byteson a pre-grown buffer;BenchmarkNewdrops from 9→2 allocs/op and ~30% faster with byte-identical output. ReimplementsHexviapkg/uhex. - stringmetric: Flatten the DP matrix to a single row-major slice, cutting allocations 15→4 and improving cache locality, plus documented metric guarantees.
🔧 Chores
- make: Cap benchmarks in the
testtarget with-benchtime=1x(compile/race smoke check) and add a dedicatedbenchtarget for real measurements; mirrored into theexamples/servicescaffold. - deps: Update dependencies.
Full Changelog: v1.138.0...v1.139.0