diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 278a3cdc..05d85d79 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -32,3 +32,33 @@ updates:
schedule:
interval: "weekly"
open-pull-requests-limit: 10
+
+ - package-ecosystem: "gomod"
+ directory: "/addons/processors/iceberg-processor"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 5
+
+ - package-ecosystem: "gomod"
+ directory: "/addons/processors/sql-processor"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 5
+
+ - package-ecosystem: "npm"
+ directory: "/lfs-client-sdk/js"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 5
+
+ - package-ecosystem: "npm"
+ directory: "/lfs-client-sdk/js-browser"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 5
+
+ - package-ecosystem: "maven"
+ directory: "/lfs-client-sdk/java"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 5
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index df754b5e..a1cf16f1 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -24,6 +24,8 @@ on:
- main
workflow_dispatch:
+permissions: read-all
+
jobs:
analyze:
name: Analyze
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 2f4bfc17..6a50ff9d 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -21,7 +21,7 @@ on:
- 'v*'
workflow_dispatch:
-permissions: {}
+permissions: read-all
jobs:
build-and-push:
diff --git a/Makefile b/Makefile
index 5cc00387..a1887f34 100644
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,7 @@ LOCAL_NODE_BIN := $(LOCAL_NODE_DIR)/bin
LOCAL_NODE := $(LOCAL_NODE_BIN)/node
LOCAL_NPM := $(LOCAL_NODE_BIN)/npm
-.PHONY: proto build test test-nested-modules tidy lint generate build-sdk docker-build docker-build-e2e-client docker-build-etcd-tools docker-clean ensure-minio start-minio stop-containers release-broker-ports test-produce-consume test-produce-consume-debug test-consumer-group test-ops-api test-mcp test-multi-segment-durability test-full test-operator test-acl demo demo-platform demo-platform-bootstrap iceberg-demo kafsql-demo platform-demo help clean-kind-all ensure-local-node check vet race fmt fmt-check test-fuzz code-ql code-ql-summary code-ql-gate commit-check test-chart-proxy-nodeport test-chart-psa test-chart-antiaffinity
+.PHONY: proto build test test-nested-modules test-lfs-sdk-unit tidy lint generate build-sdk docker-build docker-build-e2e-client docker-build-etcd-tools docker-clean ensure-minio start-minio stop-containers release-broker-ports test-produce-consume test-produce-consume-debug test-consumer-group test-ops-api test-mcp test-multi-segment-durability test-full test-operator test-acl demo demo-platform demo-platform-bootstrap iceberg-demo kafsql-demo platform-demo help clean-kind-all ensure-local-node check vet race fmt fmt-check test-fuzz code-ql code-ql-summary code-ql-gate commit-check test-chart-proxy-nodeport test-chart-psa test-chart-antiaffinity
REGISTRY ?= ghcr.io/kafscale
STAMP_DIR ?= .build
@@ -171,6 +171,15 @@ test-nested-modules: ## Run go test across nested Go modules under addons/proces
( cd $$dir && go test ./... ); \
done; \
echo "nested module tests passed."
+
+SDK_NPM := $(if $(wildcard $(LOCAL_NPM)),$(LOCAL_NPM),npm)
+
+test-lfs-sdk-unit: ensure-local-node ## Run LFS JS SDK unit tests (node + browser)
+ @echo "==> lfs-client-sdk/js: npm test"
+ @cd lfs-client-sdk/js && $(SDK_NPM) ci && $(SDK_NPM) test
+ @echo "==> lfs-client-sdk/js-browser: npm test"
+ @cd lfs-client-sdk/js-browser && $(SDK_NPM) install && $(SDK_NPM) test
+ @echo "lfs sdk unit tests passed."
vet: ## Run go vet
@echo "==> go vet"
@go vet ./...
@@ -228,7 +237,7 @@ code-ql-gate: code-ql ## Fail if CodeQL reports any error findings
fi; \
echo "CodeQL gate passed: no error findings found."
-commit-check: ensure-local-node check fmt test test-nested-modules test-fuzz code-ql-gate ## Run pre-commit quality gates
+commit-check: ensure-local-node check fmt test test-nested-modules test-lfs-sdk-unit test-fuzz code-ql-gate ## Run pre-commit quality gates
@echo "commit-check passed."
test-acl: ## Run ACL e2e test (requires KAFSCALE_E2E=1)
diff --git a/addons/processors/iceberg-processor/go.mod b/addons/processors/iceberg-processor/go.mod
index 54bf0df0..3be577ef 100644
--- a/addons/processors/iceberg-processor/go.mod
+++ b/addons/processors/iceberg-processor/go.mod
@@ -40,7 +40,7 @@ require (
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
- github.com/apache/thrift v0.22.0 // indirect
+ github.com/apache/thrift v0.23.0 // indirect
github.com/aws/aws-sdk-go v1.55.7 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.19.10 // indirect
@@ -136,18 +136,18 @@ require (
go.uber.org/zap v1.27.1 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
gocloud.dev v0.43.0 // indirect
- golang.org/x/crypto v0.48.0 // indirect
+ golang.org/x/crypto v0.51.0 // indirect
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc // indirect
- golang.org/x/mod v0.32.0 // indirect
- golang.org/x/net v0.49.0 // indirect
+ golang.org/x/mod v0.35.0 // indirect
+ golang.org/x/net v0.55.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
- golang.org/x/sync v0.19.0 // indirect
- golang.org/x/sys v0.42.0 // indirect
- golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2 // indirect
- golang.org/x/term v0.40.0 // indirect
- golang.org/x/text v0.34.0 // indirect
+ golang.org/x/sync v0.20.0 // indirect
+ golang.org/x/sys v0.45.0 // indirect
+ golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa // indirect
+ golang.org/x/term v0.43.0 // indirect
+ golang.org/x/text v0.37.0 // indirect
golang.org/x/time v0.14.0 // indirect
- golang.org/x/tools v0.41.0 // indirect
+ golang.org/x/tools v0.44.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/api v0.251.0 // indirect
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect
diff --git a/addons/processors/iceberg-processor/go.sum b/addons/processors/iceberg-processor/go.sum
index 868de46c..986cde8d 100644
--- a/addons/processors/iceberg-processor/go.sum
+++ b/addons/processors/iceberg-processor/go.sum
@@ -89,8 +89,8 @@ github.com/apache/arrow-go/v18 v18.4.1 h1:q/jVkBWCJOB9reDgaIZIdruLQUb1kbkvOnOFez
github.com/apache/arrow-go/v18 v18.4.1/go.mod h1:tLyFubsAl17bvFdUAy24bsSvA/6ww95Iqi67fTpGu3E=
github.com/apache/iceberg-go v0.4.0 h1:O3RwMyoc4gZpu9b1aBDJBiH14riga68BWypZVaSHZE0=
github.com/apache/iceberg-go v0.4.0/go.mod h1:TInpnxHnMdPrsmW/klToy9mM8gs6/6FsI+O2kwtlHMQ=
-github.com/apache/thrift v0.22.0 h1:r7mTJdj51TMDe6RtcmNdQxgn9XcyfGDOzegMDRg47uc=
-github.com/apache/thrift v0.22.0/go.mod h1:1e7J/O1Ae6ZQMTYdy9xa3w9k+XHWPfRvdPyJeynQ+/g=
+github.com/apache/thrift v0.23.0 h1:wKR6YnefQSEnxpEfmgTPuJibNG4bF0p2TK34tHLWi3s=
+github.com/apache/thrift v0.23.0/go.mod h1:zPt6WxgvTOM6hF92y8C+MkEM5LMxZuk4JcQOiU4Esvs=
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
@@ -672,8 +672,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
-golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
-golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
+golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
+golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc h1:TS73t7x3KarrNd5qAipmspBDS1rkMcgVG/fS1aRb4Rc=
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -682,8 +682,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
-golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
+golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
+golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -694,8 +694,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
-golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
-golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
+golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
+golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -705,8 +705,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -723,10 +723,10 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-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/telemetry v0.0.0-20260109210033-bd525da824e2 h1:O1cMQHRfwNpDfDJerqRoE2oD+AFlyid87D40L/OkkJo=
-golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8=
+golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
+golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa h1:efT73AJZfAAUV7SOip6pWGkwJDzIGiKBZGVzHYa+ve4=
+golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa/go.mod h1:kHjTxDEnAu6/Nl9lDkzjWpR+bmKfxeiRuSDlsMb70gE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -735,8 +735,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
-golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
-golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
+golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
+golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -744,8 +744,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
-golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
+golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
+golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -756,8 +756,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
-golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
-golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
+golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
+golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/addons/processors/sql-processor/go.mod b/addons/processors/sql-processor/go.mod
index dbc93fdc..b7f1783f 100644
--- a/addons/processors/sql-processor/go.mod
+++ b/addons/processors/sql-processor/go.mod
@@ -79,10 +79,10 @@ require (
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.17.0 // indirect
- golang.org/x/crypto v0.46.0 // indirect
- golang.org/x/net v0.48.0 // indirect
- golang.org/x/sys v0.42.0 // indirect
- golang.org/x/text v0.32.0 // indirect
+ golang.org/x/crypto v0.51.0 // indirect
+ golang.org/x/net v0.55.0 // indirect
+ golang.org/x/sys v0.45.0 // indirect
+ golang.org/x/text v0.37.0 // indirect
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
diff --git a/addons/processors/sql-processor/go.sum b/addons/processors/sql-processor/go.sum
index 93e6c6a1..760f1de9 100644
--- a/addons/processors/sql-processor/go.sum
+++ b/addons/processors/sql-processor/go.sum
@@ -225,8 +225,8 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-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.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
+golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -244,8 +244,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
-golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
+golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
+golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
@@ -256,8 +256,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -265,12 +265,12 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-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/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
+golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
-golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
+golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
+golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/docs/development.md b/docs/development.md
index 56524a1d..6dd9bbf5 100644
--- a/docs/development.md
+++ b/docs/development.md
@@ -52,7 +52,7 @@ Refer to `kafscale-spec.md` for the detailed package-by-package breakdown.
|---------|---------|
| `make build` | Compile all Go binaries. |
| `make test` | Run unit tests (includes `go vet` and race detector). |
-| `make commit-check` | Run the standard pre-PR quality gate (`check`, `fmt`, `test`, `test-fuzz`, `code-ql-gate`). |
+| `make commit-check` | Run the standard pre-PR quality gate (`check`, `fmt`, `test`, `test-nested-modules`, `test-lfs-sdk-unit`, `test-fuzz`, `code-ql-gate`). |
| `make test-produce-consume` | MinIO + Franz produce/consume e2e suite plus Kafka CLI producer smoke test (Docker image required). |
| `make test-consumer-group` | Consumer group persistence e2e (embedded etcd + memory S3). |
| `make test-ops-api` | Ops/admin API e2e (embedded etcd + memory S3). |
diff --git a/go.mod b/go.mod
index de9e138c..d1a050fb 100644
--- a/go.mod
+++ b/go.mod
@@ -14,10 +14,11 @@ require (
github.com/twmb/franz-go v1.20.7
github.com/twmb/franz-go/pkg/kadm v1.17.1
github.com/twmb/franz-go/pkg/kmsg v1.12.0
+ go.etcd.io/etcd/api/v3 v3.6.8
go.etcd.io/etcd/client/v3 v3.6.8
go.etcd.io/etcd/server/v3 v3.6.8
go.uber.org/zap v1.27.1
- golang.org/x/sync v0.19.0
+ golang.org/x/sync v0.20.0
google.golang.org/grpc v1.79.3
google.golang.org/protobuf v1.36.11
k8s.io/api v0.35.1
@@ -94,7 +95,6 @@ require (
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
go.etcd.io/bbolt v1.4.3 // indirect
- go.etcd.io/etcd/api/v3 v3.6.8 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.8 // indirect
go.etcd.io/etcd/pkg/v3 v3.6.8 // indirect
go.etcd.io/raft/v3 v3.6.0 // indirect
@@ -110,12 +110,12 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
- golang.org/x/crypto v0.48.0 // indirect
- golang.org/x/net v0.49.0 // indirect
+ golang.org/x/crypto v0.51.0 // indirect
+ golang.org/x/net v0.55.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
- golang.org/x/sys v0.42.0 // indirect
- golang.org/x/term v0.40.0 // indirect
- golang.org/x/text v0.34.0 // indirect
+ golang.org/x/sys v0.45.0 // indirect
+ golang.org/x/term v0.43.0 // indirect
+ golang.org/x/text v0.37.0 // indirect
golang.org/x/time v0.14.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect
diff --git a/go.sum b/go.sum
index 1fb25e82..afc5f5c9 100644
--- a/go.sum
+++ b/go.sum
@@ -251,27 +251,27 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
-golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
+golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
+golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
-golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
+golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
+golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
-golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
+golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
+golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -280,24 +280,24 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-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/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
+golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
-golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
+golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
+golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
-golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
+golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
+golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
-golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
+golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
+golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/lfs-client-sdk/Makefile b/lfs-client-sdk/Makefile
index e40d6bd9..680f814d 100644
--- a/lfs-client-sdk/Makefile
+++ b/lfs-client-sdk/Makefile
@@ -149,7 +149,7 @@ build-js:
@cd js && npm run build
test-js:
- @cd js && npm test
+ @cd js && npm ci && npm test
build-python:
@cd python && $(PYTHON) -c "import build" >/dev/null 2>&1 || { echo "python -m pip install build"; exit 1; }
@@ -162,7 +162,7 @@ build-js-browser:
@cd js-browser && npm run build
test-js-browser:
- @cd js-browser && npm test
+ @cd js-browser && npm install && npm test
build-all: build-java build-js build-python build-js-browser
diff --git a/lfs-client-sdk/java/pom.xml b/lfs-client-sdk/java/pom.xml
index 60bbed21..6dfb6236 100644
--- a/lfs-client-sdk/java/pom.xml
+++ b/lfs-client-sdk/java/pom.xml
@@ -31,7 +31,7 @@ limitations under the License.
UTF-8
4.1.2
2.31.5
- 2.17.2
+ 2.19.1
5.11.0
1.20.2
diff --git a/lfs-client-sdk/js-browser/package.json b/lfs-client-sdk/js-browser/package.json
index c6ffa7d9..da2d0bb0 100644
--- a/lfs-client-sdk/js-browser/package.json
+++ b/lfs-client-sdk/js-browser/package.json
@@ -22,7 +22,7 @@
"devDependencies": {
"typescript": "^5.6.0",
"esbuild": "^0.24.0",
- "vitest": "^2.0.0"
+ "vitest": "^3.2.6"
},
"files": [
"dist",
diff --git a/lfs-client-sdk/js-browser/src/__tests__/envelope.test.ts b/lfs-client-sdk/js-browser/src/__tests__/envelope.test.ts
new file mode 100644
index 00000000..e5e3649b
--- /dev/null
+++ b/lfs-client-sdk/js-browser/src/__tests__/envelope.test.ts
@@ -0,0 +1,38 @@
+import { describe, expect, it } from 'vitest';
+import { decodeLfsEnvelope, isLfsEnvelope } from '../envelope.js';
+
+const sampleEnvelope = {
+ kfs_lfs: 1,
+ bucket: 'demo-bucket',
+ key: 'default/topic/0/segment.bin',
+ size: 42,
+ sha256: 'abc123',
+};
+
+describe('isLfsEnvelope', () => {
+ it('accepts a valid envelope object', () => {
+ expect(isLfsEnvelope(sampleEnvelope)).toBe(true);
+ });
+
+ it('rejects non-objects and incomplete payloads', () => {
+ expect(isLfsEnvelope(null)).toBe(false);
+ expect(isLfsEnvelope('{"kfs_lfs":1}')).toBe(false);
+ expect(isLfsEnvelope({ kfs_lfs: 1, bucket: 'b', key: 'k' })).toBe(false);
+ expect(isLfsEnvelope({ ...sampleEnvelope, sha256: 123 })).toBe(false);
+ });
+});
+
+describe('decodeLfsEnvelope', () => {
+ it('decodes JSON strings and byte payloads', () => {
+ const json = JSON.stringify(sampleEnvelope);
+
+ expect(decodeLfsEnvelope(json)).toEqual(sampleEnvelope);
+ expect(decodeLfsEnvelope(new TextEncoder().encode(json))).toEqual(sampleEnvelope);
+ });
+
+ it('throws when required fields are missing', () => {
+ expect(() => decodeLfsEnvelope('{"kfs_lfs":1}')).toThrow(
+ 'Invalid LFS envelope: missing required fields'
+ );
+ });
+});
\ No newline at end of file
diff --git a/lfs-client-sdk/js-browser/src/__tests__/producer.test.ts b/lfs-client-sdk/js-browser/src/__tests__/producer.test.ts
new file mode 100644
index 00000000..c2250930
--- /dev/null
+++ b/lfs-client-sdk/js-browser/src/__tests__/producer.test.ts
@@ -0,0 +1,246 @@
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
+import { LfsHttpError, LfsProducer, produceLfs } from '../producer.js';
+
+const sampleEnvelope = {
+ kfs_lfs: 1,
+ bucket: 'demo-bucket',
+ key: 'default/topic/0/segment.bin',
+ size: 5,
+ sha256: 'abc123',
+};
+
+class MockXMLHttpRequest {
+ static instances: MockXMLHttpRequest[] = [];
+
+ method = '';
+ url = '';
+ async = false;
+ status = 0;
+ responseText = '';
+ requestHeaders: Record = {};
+ upload = { onprogress: null as ((event: ProgressEvent) => void) | null };
+ onload: (() => void) | null = null;
+ onerror: (() => void) | null = null;
+ onabort: (() => void) | null = null;
+ sentBody: Blob | null = null;
+
+ constructor() {
+ MockXMLHttpRequest.instances.push(this);
+ }
+
+ open(method: string, url: string, async: boolean) {
+ this.method = method;
+ this.url = url;
+ this.async = async;
+ }
+
+ setRequestHeader(key: string, value: string) {
+ this.requestHeaders[key] = value;
+ }
+
+ send(body?: Blob) {
+ this.sentBody = body ?? null;
+ queueMicrotask(() => responder(this, MockXMLHttpRequest.instances.length));
+ }
+
+ abort() {
+ this.onabort?.();
+ }
+
+ succeed(body: unknown, status = 200) {
+ this.status = status;
+ this.responseText = JSON.stringify(body);
+ this.onload?.();
+ }
+
+ fail(status: number, body: string | Record) {
+ this.status = status;
+ this.responseText = typeof body === 'string' ? body : JSON.stringify(body);
+ this.onload?.();
+ }
+
+ networkError() {
+ this.onerror?.();
+ }
+
+ emitProgress(loaded: number, total: number) {
+ this.upload.onprogress?.({
+ lengthComputable: true,
+ loaded,
+ total,
+ } as ProgressEvent);
+ }
+}
+
+let responder: (xhr: MockXMLHttpRequest, attempt: number) => void = () => {
+ throw new Error('XMLHttpRequest responder not configured');
+};
+
+beforeEach(() => {
+ MockXMLHttpRequest.instances = [];
+ responder = () => {
+ throw new Error('XMLHttpRequest responder not configured');
+ };
+
+ vi.stubGlobal('XMLHttpRequest', MockXMLHttpRequest as unknown as typeof XMLHttpRequest);
+ vi.stubGlobal('crypto', {
+ randomUUID: () => 'test-request-id',
+ });
+});
+
+afterEach(() => {
+ vi.useRealTimers();
+ vi.restoreAllMocks();
+});
+
+describe('LfsProducer', () => {
+ it('uploads payloads and returns the proxy envelope', async () => {
+ responder = (xhr) => xhr.succeed(sampleEnvelope);
+
+ const producer = new LfsProducer({ endpoint: 'https://proxy.example/lfs' });
+ const payload = new Blob(['hello'], { type: 'text/plain' });
+ const envelope = await producer.produce('orders', payload, { key: 'order-1' });
+
+ expect(envelope).toEqual(sampleEnvelope);
+ expect(MockXMLHttpRequest.instances).toHaveLength(1);
+
+ const xhr = MockXMLHttpRequest.instances[0];
+ expect(xhr.method).toBe('POST');
+ expect(xhr.url).toBe('https://proxy.example/lfs');
+ expect(xhr.requestHeaders).toMatchObject({
+ 'X-Kafka-Topic': 'orders',
+ 'X-Kafka-Key': 'order-1',
+ 'X-Request-ID': 'test-request-id',
+ 'X-LFS-Size': '5',
+ 'X-LFS-Mode': 'single',
+ 'Content-Type': 'text/plain',
+ });
+ expect(xhr.sentBody).toBe(payload);
+ });
+
+ it('uses multipart mode for large payloads', async () => {
+ responder = (xhr) => xhr.succeed(sampleEnvelope);
+
+ const producer = new LfsProducer({ endpoint: 'https://proxy.example/lfs' });
+ await producer.produce('orders', new Blob([new Uint8Array(5 * 1024 * 1024)]));
+
+ expect(MockXMLHttpRequest.instances[0].requestHeaders['X-LFS-Mode']).toBe('multipart');
+ });
+
+ it('reports upload progress', async () => {
+ responder = (xhr) => {
+ xhr.emitProgress(25, 100);
+ xhr.succeed(sampleEnvelope);
+ };
+
+ const onProgress = vi.fn();
+ const producer = new LfsProducer({ endpoint: 'https://proxy.example/lfs' });
+ await producer.produce('orders', new Blob(['hello']), { onProgress });
+
+ expect(onProgress).toHaveBeenCalledWith({
+ loaded: 25,
+ total: 100,
+ percent: 25,
+ });
+ });
+
+ it('maps 4xx responses to LfsHttpError without retrying', async () => {
+ responder = (xhr) =>
+ xhr.fail(404, {
+ code: 'TOPIC_NOT_FOUND',
+ message: 'topic missing',
+ request_id: 'server-request-id',
+ });
+
+ const producer = new LfsProducer({
+ endpoint: 'https://proxy.example/lfs',
+ retries: 3,
+ retryDelay: 10,
+ });
+
+ await expect(producer.produce('orders', new Blob(['hello']))).rejects.toSatisfy(
+ (error: unknown) =>
+ error instanceof LfsHttpError &&
+ error.statusCode === 404 &&
+ error.code === 'TOPIC_NOT_FOUND' &&
+ error.message === 'topic missing' &&
+ error.requestId === 'server-request-id'
+ );
+ expect(MockXMLHttpRequest.instances).toHaveLength(1);
+ });
+
+ it('retries 5xx failures before succeeding', async () => {
+ vi.useFakeTimers();
+
+ let attempts = 0;
+ responder = (xhr) => {
+ attempts += 1;
+ if (attempts < 3) {
+ xhr.fail(503, 'temporary outage');
+ return;
+ }
+ xhr.succeed(sampleEnvelope);
+ };
+
+ const producer = new LfsProducer({
+ endpoint: 'https://proxy.example/lfs',
+ retries: 3,
+ retryDelay: 10,
+ });
+
+ const promise = producer.produce('orders', new Blob(['hello']));
+ await vi.runAllTimersAsync();
+ const envelope = await promise;
+
+ expect(envelope).toEqual(sampleEnvelope);
+ expect(MockXMLHttpRequest.instances).toHaveLength(3);
+ });
+
+ it('rejects invalid JSON responses', async () => {
+ responder = (xhr) => {
+ xhr.status = 200;
+ xhr.responseText = 'not-json';
+ xhr.onload?.();
+ };
+
+ const producer = new LfsProducer({ endpoint: 'https://proxy.example/lfs', retries: 1 });
+ await expect(producer.produce('orders', new Blob(['hello']))).rejects.toThrow(
+ 'Invalid JSON response'
+ );
+ });
+
+ it('propagates abort signals', async () => {
+ responder = () => {
+ // Keep the request pending until the caller aborts it.
+ };
+
+ const controller = new AbortController();
+ const producer = new LfsProducer({ endpoint: 'https://proxy.example/lfs', retries: 3 });
+ const promise = producer.produce('orders', new Blob(['hello']), {
+ signal: controller.signal,
+ });
+
+ await Promise.resolve();
+ controller.abort();
+
+ await expect(promise).rejects.toSatisfy(
+ (error: unknown) => error instanceof DOMException && error.name === 'AbortError'
+ );
+ expect(MockXMLHttpRequest.instances).toHaveLength(1);
+ });
+});
+
+describe('produceLfs', () => {
+ it('uploads via the convenience helper', async () => {
+ responder = (xhr) => xhr.succeed(sampleEnvelope);
+
+ const envelope = await produceLfs(
+ 'https://proxy.example/lfs',
+ 'orders',
+ new Blob(['hello'])
+ );
+
+ expect(envelope).toEqual(sampleEnvelope);
+ expect(MockXMLHttpRequest.instances[0].requestHeaders['X-Kafka-Topic']).toBe('orders');
+ });
+});
\ No newline at end of file
diff --git a/lfs-client-sdk/js-browser/src/__tests__/resolver.test.ts b/lfs-client-sdk/js-browser/src/__tests__/resolver.test.ts
new file mode 100644
index 00000000..eda31a76
--- /dev/null
+++ b/lfs-client-sdk/js-browser/src/__tests__/resolver.test.ts
@@ -0,0 +1,87 @@
+import { afterEach, describe, expect, it, vi } from 'vitest';
+import { LfsResolver } from '../resolver.js';
+
+const helloBytes = new TextEncoder().encode('hello');
+const helloSha256 = '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824';
+
+const sampleEnvelope = {
+ kfs_lfs: 1,
+ bucket: 'demo-bucket',
+ key: 'default/topic/0/segment.bin',
+ size: helloBytes.length,
+ sha256: helloSha256,
+};
+
+afterEach(() => {
+ vi.restoreAllMocks();
+});
+
+describe('LfsResolver', () => {
+ it('returns plain payloads unchanged when input is not an envelope', async () => {
+ const resolver = new LfsResolver({
+ getBlobUrl: () => 'https://example.invalid/blob',
+ });
+
+ const result = await resolver.resolve('plain-text');
+
+ expect(result.isEnvelope).toBe(false);
+ expect(new TextDecoder().decode(result.payload)).toBe('plain-text');
+ expect(result.envelope).toBeUndefined();
+ });
+
+ it('fetches and validates envelope blobs', async () => {
+ const getBlobUrl = vi.fn().mockResolvedValue('https://example.invalid/blob');
+ const fetchMock = vi.fn().mockResolvedValue({
+ ok: true,
+ arrayBuffer: async () => helloBytes.buffer,
+ });
+ vi.stubGlobal('fetch', fetchMock);
+
+ const resolver = new LfsResolver({ getBlobUrl });
+ const result = await resolver.resolve(sampleEnvelope);
+
+ expect(getBlobUrl).toHaveBeenCalledWith(sampleEnvelope.key, sampleEnvelope.bucket);
+ expect(fetchMock).toHaveBeenCalledWith('https://example.invalid/blob');
+ expect(result.isEnvelope).toBe(true);
+ expect(result.envelope).toEqual(sampleEnvelope);
+ expect(result.payload).toEqual(helloBytes);
+ });
+
+ it('rejects blobs that exceed maxSize', async () => {
+ vi.stubGlobal(
+ 'fetch',
+ vi.fn().mockResolvedValue({
+ ok: true,
+ arrayBuffer: async () => helloBytes.buffer,
+ })
+ );
+
+ const resolver = new LfsResolver({
+ getBlobUrl: async () => 'https://example.invalid/blob',
+ maxSize: 2,
+ validateChecksum: false,
+ });
+
+ await expect(resolver.resolve(sampleEnvelope)).rejects.toThrow(
+ 'Payload exceeds max size: 5 > 2'
+ );
+ });
+
+ it('rejects checksum mismatches', async () => {
+ vi.stubGlobal(
+ 'fetch',
+ vi.fn().mockResolvedValue({
+ ok: true,
+ arrayBuffer: async () => helloBytes.buffer,
+ })
+ );
+
+ const resolver = new LfsResolver({
+ getBlobUrl: async () => 'https://example.invalid/blob',
+ });
+
+ await expect(
+ resolver.resolve({ ...sampleEnvelope, sha256: 'deadbeef' })
+ ).rejects.toThrow('Checksum mismatch');
+ });
+});
\ No newline at end of file
diff --git a/lfs-client-sdk/js-browser/vitest.config.ts b/lfs-client-sdk/js-browser/vitest.config.ts
new file mode 100644
index 00000000..68537552
--- /dev/null
+++ b/lfs-client-sdk/js-browser/vitest.config.ts
@@ -0,0 +1,8 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ environment: 'node',
+ include: ['src/**/*.test.ts'],
+ },
+});
\ No newline at end of file
diff --git a/lfs-client-sdk/js/package-lock.json b/lfs-client-sdk/js/package-lock.json
index ee26b86c..b4eb98d2 100644
--- a/lfs-client-sdk/js/package-lock.json
+++ b/lfs-client-sdk/js/package-lock.json
@@ -10,7 +10,7 @@
"dependencies": {
"@aws-sdk/client-s3": "^3.1008.0",
"@confluentinc/kafka-javascript": "^1.8.2",
- "undici": "^6.24.0"
+ "undici": "^6.27.0"
},
"devDependencies": {
"@types/node": "^24.5.2",
@@ -1742,9 +1742,9 @@
}
},
"node_modules/fast-xml-builder": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz",
- "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.1.tgz",
+ "integrity": "sha512-tPb5TTWfgfVx5BNSi2xV0eLr89POeXXn0dXIsCJ9m1narrWxeIyx6je9d7Rce/3NyXLbvuQmLkxq+RuxMWejvw==",
"funding": [
{
"type": "github",
@@ -1753,7 +1753,8 @@
],
"license": "MIT",
"dependencies": {
- "path-expression-matcher": "^1.1.3"
+ "path-expression-matcher": "^1.5.0",
+ "xml-naming": "^0.1.0"
}
},
"node_modules/fast-xml-parser": {
@@ -1864,9 +1865,9 @@
}
},
"node_modules/path-expression-matcher": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz",
- "integrity": "sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.1.tgz",
+ "integrity": "sha512-h7bxdzhHk8Knyc4Tj+jMaa7fEEoUJy7p1qtbVgkYg1Uhpe5Np5VuGXCRZnkZvU+Q42M1vStt0ifa3ueykRJPmQ==",
"funding": [
{
"type": "github",
@@ -1903,9 +1904,9 @@
"license": "MIT"
},
"node_modules/tar": {
- "version": "7.5.11",
- "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz",
- "integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==",
+ "version": "7.5.19",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.19.tgz",
+ "integrity": "sha512-4LeEWl96twnS2Q7Bz4MGqgazLqO+hJN63GZxXoIqh1T3VweYD997gbU1ItNsQafqqXTXd5WFyFdReLtwvRBNiw==",
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/fs-minipass": "^4.0.0",
@@ -1945,9 +1946,9 @@
}
},
"node_modules/undici": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz",
- "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==",
+ "version": "6.27.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz",
+ "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==",
"license": "MIT",
"engines": {
"node": ">=18.17"
@@ -1976,6 +1977,21 @@
"webidl-conversions": "^3.0.0"
}
},
+ "node_modules/xml-naming": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz",
+ "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
"node_modules/yallist": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
@@ -2687,7 +2703,7 @@
"node-fetch": "^2.6.7",
"nopt": "^8.0.0",
"semver": "^7.5.3",
- "tar": "7.5.11"
+ "tar": "7.5.19"
}
},
"@smithy/abort-controller": {
@@ -3275,11 +3291,12 @@
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="
},
"fast-xml-builder": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz",
- "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.1.tgz",
+ "integrity": "sha512-tPb5TTWfgfVx5BNSi2xV0eLr89POeXXn0dXIsCJ9m1narrWxeIyx6je9d7Rce/3NyXLbvuQmLkxq+RuxMWejvw==",
"requires": {
- "path-expression-matcher": "^1.1.3"
+ "path-expression-matcher": "^1.5.0",
+ "xml-naming": "^0.1.0"
}
},
"fast-xml-parser": {
@@ -3287,7 +3304,7 @@
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.8.tgz",
"integrity": "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==",
"requires": {
- "fast-xml-builder": "^1.1.4",
+ "fast-xml-builder": "1.2.1",
"path-expression-matcher": "^1.2.0",
"strnum": "^2.2.0"
}
@@ -3346,9 +3363,9 @@
}
},
"path-expression-matcher": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz",
- "integrity": "sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ=="
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.1.tgz",
+ "integrity": "sha512-h7bxdzhHk8Knyc4Tj+jMaa7fEEoUJy7p1qtbVgkYg1Uhpe5Np5VuGXCRZnkZvU+Q42M1vStt0ifa3ueykRJPmQ=="
},
"semver": {
"version": "7.7.4",
@@ -3361,9 +3378,9 @@
"integrity": "sha512-BwRvNd5/QoAtyW1na1y1LsJGQNvRlkde6Q/ipqqEaivoMdV+B1OMOTVdwR+N/cwVUcIt9PYyHmV8HyexCZSupg=="
},
"tar": {
- "version": "7.5.11",
- "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz",
- "integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==",
+ "version": "7.5.19",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.19.tgz",
+ "integrity": "sha512-4LeEWl96twnS2Q7Bz4MGqgazLqO+hJN63GZxXoIqh1T3VweYD997gbU1ItNsQafqqXTXd5WFyFdReLtwvRBNiw==",
"requires": {
"@isaacs/fs-minipass": "^4.0.0",
"chownr": "^3.0.0",
@@ -3389,9 +3406,9 @@
"dev": true
},
"undici": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz",
- "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA=="
+ "version": "6.27.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz",
+ "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg=="
},
"undici-types": {
"version": "7.16.0",
@@ -3413,6 +3430,11 @@
"webidl-conversions": "^3.0.0"
}
},
+ "xml-naming": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz",
+ "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw=="
+ },
"yallist": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
diff --git a/lfs-client-sdk/js/package.json b/lfs-client-sdk/js/package.json
index 87e89644..a6706cec 100644
--- a/lfs-client-sdk/js/package.json
+++ b/lfs-client-sdk/js/package.json
@@ -12,7 +12,7 @@
"dependencies": {
"@aws-sdk/client-s3": "^3.1008.0",
"@confluentinc/kafka-javascript": "^1.8.2",
- "undici": "^6.24.0"
+ "undici": "^6.27.0"
},
"overrides": {
"@aws-sdk/xml-builder": "3.972.10",
@@ -20,8 +20,9 @@
"fast-xml-parser": "5.5.8"
},
"@tootallnate/once": "3.0.1",
- "tar": "7.5.11",
- "fast-xml-parser": "5.5.8"
+ "tar": "7.5.19",
+ "fast-xml-parser": "5.5.8",
+ "fast-xml-builder": "1.2.1"
},
"devDependencies": {
"@types/node": "^24.5.2",
diff --git a/pkg/metadata/etcd_store.go b/pkg/metadata/etcd_store.go
index fa3abec7..7d8f2ff8 100644
--- a/pkg/metadata/etcd_store.go
+++ b/pkg/metadata/etcd_store.go
@@ -51,7 +51,7 @@ type EtcdStore struct {
cancel context.CancelFunc
available int32
lastError atomic.Value // stores etcdError
- persistMu sync.Mutex // serializes snapshot read/write to avoid out-of-order etcd puts
+ persistMu sync.Mutex // serializes snapshot read/write to avoid out-of-order etcd puts
}
func (s *EtcdStore) EtcdClient() *clientv3.Client {