Compare commits

...

10 Commits

Author SHA1 Message Date
0cc3635466 chore(deps): update Go dependencies
Some checks failed
Build , Vet Test, and Lint / Run Vet Tests (1.24.x) (push) Successful in 2m9s
Build , Vet Test, and Lint / Build (push) Successful in 1m21s
Tests / Unit Tests (push) Failing after 1m5s
Build , Vet Test, and Lint / Run Vet Tests (1.23.x) (push) Successful in -23m55s
Build , Vet Test, and Lint / Lint Code (push) Successful in -23m56s
Tests / Integration Tests (push) Failing after 59s
- Update github.com/jackc/pgx/v5 from v5.6.0 to v5.8.0
- Update github.com/klauspost/compress from v1.18.0 to v1.18.2
- Update github.com/mattn/go-sqlite3 from v1.14.32 to v1.14.33
- Update github.com/redis/go-redis/v9 from v9.17.1 to v9.17.2
- Update go.uber.org/zap from v1.27.0 to v1.27.1
- Update golang.org/x/crypto from v0.43.0 to v0.46.0
- Update gorm.io/gorm from v1.30.0 to v1.31.1
- Update various indirect dependencies
2026-01-03 22:06:31 +02:00
c2d86c9880 fix(dbmanager): resolve deadlock in adapter getter methods
Some checks failed
Build , Vet Test, and Lint / Run Vet Tests (1.24.x) (push) Successful in 30s
Build , Vet Test, and Lint / Build (push) Successful in 1m56s
Tests / Unit Tests (push) Failing after 1m5s
Tests / Integration Tests (push) Failing after 1m1s
Build , Vet Test, and Lint / Run Vet Tests (1.23.x) (push) Successful in -23m15s
Build , Vet Test, and Lint / Lint Code (push) Successful in -23m9s
Fixes deadlock caused by calling public methods (Bun, GORM, Native)
while holding a write lock. The public methods attempt to acquire
their own locks, causing the goroutine to freeze.

Solution: Call provider methods directly within the adapter getters
since they already hold the necessary write lock.
2026-01-03 17:26:43 +02:00
70bf0a4be1 fix(dbmanager): add nil checks to connection methods 2026-01-03 17:19:43 +02:00
4964d89158 feat(restheadspec): accept bunrouter.Router and bunrouter.Group in SetupBunRouterRoutes
Replaced *router.StandardBunRouterAdapter parameter with BunRouterHandler
interface to support both bunrouter.Router and bunrouter.Group types,
enabling route registration on router groups with path prefixes.

- Added BunRouterHandler interface
- Updated SetupBunRouterRoutes signature
- Updated ExampleBunRouterWithBunDB to use bunrouter.New() directly
- Added ExampleBunRouterWithGroup demonstrating group usage
2026-01-03 16:10:36 +02:00
96b098f912 feat(resolvespec): accept bunrouter.Router and bunrouter.Group in SetupBunRouterRoutes
Replaced *router.StandardBunRouterAdapter parameter with BunRouterHandler
interface to support both bunrouter.Router and bunrouter.Group types,
enabling route registration on router groups with path prefixes.

- Added BunRouterHandler interface
- Updated SetupBunRouterRoutes signature
- Updated example functions to use bunrouter.New() directly
- Added ExampleBunRouterWithGroup demonstrating group usage
2026-01-03 16:06:53 +02:00
5bba99efe3 Merge branch 'main' of github.com:bitechdev/ResolveSpec 2026-01-03 14:48:17 +02:00
8504b6d13d fix(staticweb): add nil check to WithStripPrefix helper
Prevent panic when WithStripPrefix is called with a nil provider by
using reflection to check for typed nil pointers stored in interfaces.
2026-01-03 14:47:21 +02:00
ada4db6465 fix(staticweb): add nil check to WithStripPrefix helper
Prevent panic when WithStripPrefix is called with a nil provider.
2026-01-03 14:43:31 +02:00
2017465cb8 feat(staticweb): add path prefix stripping to all filesystem providers
Add PrefixStrippingProvider interface and implement it in all providers
(EmbedFSProvider, LocalFSProvider, ZipFSProvider) to support serving
files from subdirectories at the root level.
2026-01-03 14:39:51 +02:00
d33747c2d3 feat(staticweb): add path prefix stripping to EmbedFSProvider
Adds WithStripPrefix method to allow serving files from subdirectories
at the root path. For example, files at /dist/assets can be made
accessible via /assets by calling WithStripPrefix("/dist").
2026-01-03 14:25:04 +02:00
9 changed files with 373 additions and 69 deletions

52
go.mod
View File

@@ -13,14 +13,14 @@ require (
github.com/google/uuid v1.6.0
github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.3
github.com/jackc/pgx/v5 v5.6.0
github.com/klauspost/compress v1.18.0
github.com/mattn/go-sqlite3 v1.14.32
github.com/jackc/pgx/v5 v5.8.0
github.com/klauspost/compress v1.18.2
github.com/mattn/go-sqlite3 v1.14.33
github.com/microsoft/go-mssqldb v1.9.5
github.com/mochi-mqtt/server/v2 v2.7.9
github.com/nats-io/nats.go v1.48.0
github.com/prometheus/client_golang v1.23.2
github.com/redis/go-redis/v9 v9.17.1
github.com/redis/go-redis/v9 v9.17.2
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1
github.com/testcontainers/testcontainers-go v0.40.0
@@ -38,13 +38,13 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0
go.opentelemetry.io/otel/sdk v1.38.0
go.opentelemetry.io/otel/trace v1.38.0
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.43.0
go.uber.org/zap v1.27.1
golang.org/x/crypto v0.46.0
golang.org/x/time v0.14.0
gorm.io/driver/postgres v1.6.0
gorm.io/driver/sqlite v1.6.0
gorm.io/driver/sqlserver v1.6.3
gorm.io/gorm v1.30.0
gorm.io/gorm v1.31.1
)
require (
@@ -70,14 +70,14 @@ require (
github.com/ebitengine/purego v0.8.4 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/glebarez/go-sqlite v1.22.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
@@ -107,12 +107,12 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/prometheus/common v0.67.4 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rs/xid v1.4.0 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/shirou/gopsutil/v4 v4.25.6 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
@@ -122,15 +122,15 @@ require (
github.com/spf13/pflag v1.0.10 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tidwall/match v1.2.0 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/scram v1.2.0 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
@@ -138,24 +138,24 @@ require (
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
go.uber.org/multierr v1.10.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
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/exp v0.0.0-20251113190631-e25ba8c21ef6 // indirect
golang.org/x/mod v0.30.0 // indirect
golang.org/x/net v0.45.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/text v0.30.0 // indirect
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
golang.org/x/mod v0.31.0 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
google.golang.org/grpc v1.75.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.67.0 // indirect
modernc.org/libc v1.67.4 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.40.1 // indirect
modernc.org/sqlite v1.42.2 // indirect
)
replace github.com/uptrace/bun => github.com/warkanum/bun v1.2.17

55
go.sum
View File

@@ -90,6 +90,8 @@ github.com/getsentry/sentry-go v0.40.0 h1:VTJMN9zbTvqDqPwheRVLcp0qcUcM+8eFivvGoc
github.com/getsentry/sentry-go v0.40.0/go.mod h1:eRXCoh3uvmjQLY6qu63BjUZnaBu5L5WhMV1RwYO8W5s=
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
@@ -107,6 +109,7 @@ github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVI
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
@@ -115,6 +118,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
@@ -142,6 +147,8 @@ github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7Ulw
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo=
github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
@@ -159,6 +166,8 @@ github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
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/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -176,6 +185,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0=
github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/microsoft/go-mssqldb v1.8.2/go.mod h1:vp38dT33FGfVotRiTmDo3bFyaHq+p3LektQrjTULowo=
github.com/microsoft/go-mssqldb v1.9.5 h1:orwya0X/5bsL1o+KasupTkk2eNTNFkTQG0BEe/HxCn0=
github.com/microsoft/go-mssqldb v1.9.5/go.mod h1:VCP2a0KEZZtGLRHd1PsLavLFYy/3xX2yJUPycv3Sr2Q=
@@ -237,12 +248,18 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc=
github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/redis/go-redis/v9 v9.17.1 h1:7tl732FjYPRT9H9aNfyTwKg9iTETjWjGKEJ2t/5iWTs=
github.com/redis/go-redis/v9 v9.17.1/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
github.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI=
github.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
@@ -253,6 +270,8 @@ github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4=
github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=
github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
@@ -293,8 +312,12 @@ github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM=
github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
@@ -323,6 +346,8 @@ github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
@@ -358,10 +383,16 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
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=
@@ -378,8 +409,12 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
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/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0=
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@@ -388,6 +423,8 @@ golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@@ -407,6 +444,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -416,6 +455,8 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -441,6 +482,8 @@ golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
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/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -458,6 +501,7 @@ golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
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=
@@ -474,6 +518,8 @@ golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
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/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=
@@ -484,6 +530,7 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
@@ -496,6 +543,8 @@ google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -514,6 +563,8 @@ gorm.io/driver/sqlserver v1.6.3 h1:UR+nWCuphPnq7UxnL57PSrlYjuvs+sf1N59GgFX7uAI=
gorm.io/driver/sqlserver v1.6.3/go.mod h1:VZeNn7hqX1aXoN5TPAFGWvxWG90xtA8erGn2gQmpc6U=
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
@@ -530,6 +581,8 @@ modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.67.0 h1:QzL4IrKab2OFmxA3/vRYl0tLXrIamwrhD6CKD4WBVjQ=
modernc.org/libc v1.67.0/go.mod h1:QvvnnJ5P7aitu0ReNpVIEyesuhmDLQ8kaEoyMjIFZJA=
modernc.org/libc v1.67.4 h1:zZGmCMUVPORtKv95c2ReQN5VDjvkoRm9GWPTEPuvlWg=
modernc.org/libc v1.67.4/go.mod h1:QvvnnJ5P7aitu0ReNpVIEyesuhmDLQ8kaEoyMjIFZJA=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
@@ -540,6 +593,8 @@ modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.40.1 h1:VfuXcxcUWWKRBuP8+BR9L7VnmusMgBNNnBYGEe9w/iY=
modernc.org/sqlite v1.40.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE=
modernc.org/sqlite v1.42.2 h1:7hkZUNJvJFN2PgfUdjni9Kbvd4ef4mNLOu0B9FGxM74=
modernc.org/sqlite v1.42.2/go.mod h1:+VkC6v3pLOAE0A0uVucQEcbVW0I5nHCeDaBf+DpsQT8=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=

View File

@@ -3,6 +3,7 @@ package dbmanager
import (
"context"
"database/sql"
"fmt"
"sync"
"time"
@@ -159,6 +160,9 @@ func (c *sqlConnection) Close() error {
// HealthCheck verifies the connection is alive
func (c *sqlConnection) HealthCheck(ctx context.Context) error {
if c == nil {
return fmt.Errorf("connection is nil")
}
c.mu.Lock()
defer c.mu.Unlock()
@@ -188,6 +192,9 @@ func (c *sqlConnection) Reconnect(ctx context.Context) error {
// Native returns the native *sql.DB connection
func (c *sqlConnection) Native() (*sql.DB, error) {
if c == nil {
return nil, fmt.Errorf("connection is nil")
}
c.mu.RLock()
if c.nativeDB != nil {
defer c.mu.RUnlock()
@@ -219,6 +226,9 @@ func (c *sqlConnection) Native() (*sql.DB, error) {
// Bun returns a Bun ORM instance wrapping the native connection
func (c *sqlConnection) Bun() (*bun.DB, error) {
if c == nil {
return nil, fmt.Errorf("connection is nil")
}
c.mu.RLock()
if c.bunDB != nil {
defer c.mu.RUnlock()
@@ -249,6 +259,9 @@ func (c *sqlConnection) Bun() (*bun.DB, error) {
// GORM returns a GORM instance wrapping the native connection
func (c *sqlConnection) GORM() (*gorm.DB, error) {
if c == nil {
return nil, fmt.Errorf("connection is nil")
}
c.mu.RLock()
if c.gormDB != nil {
defer c.mu.RUnlock()
@@ -283,6 +296,9 @@ func (c *sqlConnection) GORM() (*gorm.DB, error) {
// Database returns the common.Database interface using the configured default ORM
func (c *sqlConnection) Database() (common.Database, error) {
if c == nil {
return nil, fmt.Errorf("connection is nil")
}
c.mu.RLock()
defaultORM := c.config.DefaultORM
c.mu.RUnlock()
@@ -307,6 +323,9 @@ func (c *sqlConnection) MongoDB() (*mongo.Client, error) {
// Stats returns connection statistics
func (c *sqlConnection) Stats() *ConnectionStats {
if c == nil {
return nil
}
c.mu.RLock()
defer c.mu.RUnlock()
@@ -336,6 +355,9 @@ func (c *sqlConnection) Stats() *ConnectionStats {
// getBunAdapter returns or creates the Bun adapter
func (c *sqlConnection) getBunAdapter() (common.Database, error) {
if c == nil {
return nil, fmt.Errorf("connection is nil")
}
c.mu.RLock()
if c.bunAdapter != nil {
defer c.mu.RUnlock()
@@ -350,17 +372,28 @@ func (c *sqlConnection) getBunAdapter() (common.Database, error) {
return c.bunAdapter, nil
}
bunDB, err := c.Bun()
if err != nil {
return nil, err
// Double-check bunDB exists (while already holding write lock)
if c.bunDB == nil {
// Get native connection first
native, err := c.provider.GetNative()
if err != nil {
return nil, NewConnectionError(c.name, "get bun", err)
}
// Create Bun DB wrapping the same sql.DB
dialect := c.getBunDialect()
c.bunDB = bun.NewDB(native, dialect)
}
c.bunAdapter = database.NewBunAdapter(bunDB)
c.bunAdapter = database.NewBunAdapter(c.bunDB)
return c.bunAdapter, nil
}
// getGORMAdapter returns or creates the GORM adapter
func (c *sqlConnection) getGORMAdapter() (common.Database, error) {
if c == nil {
return nil, fmt.Errorf("connection is nil")
}
c.mu.RLock()
if c.gormAdapter != nil {
defer c.mu.RUnlock()
@@ -375,17 +408,33 @@ func (c *sqlConnection) getGORMAdapter() (common.Database, error) {
return c.gormAdapter, nil
}
gormDB, err := c.GORM()
if err != nil {
return nil, err
// Double-check gormDB exists (while already holding write lock)
if c.gormDB == nil {
// Get native connection first
native, err := c.provider.GetNative()
if err != nil {
return nil, NewConnectionError(c.name, "get gorm", err)
}
// Create GORM DB wrapping the same sql.DB
dialector := c.getGORMDialector(native)
db, err := gorm.Open(dialector, &gorm.Config{})
if err != nil {
return nil, NewConnectionError(c.name, "initialize gorm", err)
}
c.gormDB = db
}
c.gormAdapter = database.NewGormAdapter(gormDB)
c.gormAdapter = database.NewGormAdapter(c.gormDB)
return c.gormAdapter, nil
}
// getNativeAdapter returns or creates the native adapter
func (c *sqlConnection) getNativeAdapter() (common.Database, error) {
if c == nil {
return nil, fmt.Errorf("connection is nil")
}
c.mu.RLock()
if c.nativeAdapter != nil {
defer c.mu.RUnlock()
@@ -400,21 +449,31 @@ func (c *sqlConnection) getNativeAdapter() (common.Database, error) {
return c.nativeAdapter, nil
}
native, err := c.Native()
if err != nil {
return nil, err
// Double-check nativeDB exists (while already holding write lock)
if c.nativeDB == nil {
if !c.connected {
return nil, ErrConnectionClosed
}
// Get native connection from provider
db, err := c.provider.GetNative()
if err != nil {
return nil, NewConnectionError(c.name, "get native", err)
}
c.nativeDB = db
}
// Create a native adapter based on database type
switch c.dbType {
case DatabaseTypePostgreSQL:
c.nativeAdapter = database.NewPgSQLAdapter(native)
c.nativeAdapter = database.NewPgSQLAdapter(c.nativeDB)
case DatabaseTypeSQLite:
// For SQLite, we'll use the PgSQL adapter as it works with standard sql.DB
c.nativeAdapter = database.NewPgSQLAdapter(native)
c.nativeAdapter = database.NewPgSQLAdapter(c.nativeDB)
case DatabaseTypeMSSQL:
// For MSSQL, we'll use the PgSQL adapter as it works with standard sql.DB
c.nativeAdapter = database.NewPgSQLAdapter(native)
c.nativeAdapter = database.NewPgSQLAdapter(c.nativeDB)
default:
return nil, ErrUnsupportedDatabase
}
@@ -424,6 +483,7 @@ func (c *sqlConnection) getNativeAdapter() (common.Database, error) {
// getBunDialect returns the appropriate Bun dialect for the database type
func (c *sqlConnection) getBunDialect() schema.Dialect {
switch c.dbType {
case DatabaseTypePostgreSQL:
return database.GetPostgresDialect()

View File

@@ -207,9 +207,14 @@ func ExampleWithBun(bunDB *bun.DB) {
SetupMuxRoutes(muxRouter, handler, nil)
}
// BunRouterHandler is an interface that both bunrouter.Router and bunrouter.Group implement
type BunRouterHandler interface {
Handle(method, path string, handler bunrouter.HandlerFunc)
}
// SetupBunRouterRoutes sets up bunrouter routes for the ResolveSpec API
func SetupBunRouterRoutes(bunRouter *router.StandardBunRouterAdapter, handler *Handler) {
r := bunRouter.GetBunRouter()
// Accepts bunrouter.Router or bunrouter.Group
func SetupBunRouterRoutes(r BunRouterHandler, handler *Handler) {
// CORS config
corsConfig := common.DefaultCORSConfig()
@@ -337,13 +342,13 @@ func ExampleWithBunRouter(bunDB *bun.DB) {
handler := NewHandlerWithBun(bunDB)
// Create bunrouter
bunRouter := router.NewStandardBunRouterAdapter()
bunRouter := bunrouter.New()
// Setup ResolveSpec routes with bunrouter
SetupBunRouterRoutes(bunRouter, handler)
// Start server
// http.ListenAndServe(":8080", bunRouter.GetBunRouter())
// http.ListenAndServe(":8080", bunRouter)
}
// ExampleBunRouterWithBunDB shows the full uptrace stack (bunrouter + Bun ORM)
@@ -359,11 +364,29 @@ func ExampleBunRouterWithBunDB(bunDB *bun.DB) {
handler := NewHandler(dbAdapter, registry)
// Create bunrouter
bunRouter := router.NewStandardBunRouterAdapter()
bunRouter := bunrouter.New()
// Setup ResolveSpec routes
SetupBunRouterRoutes(bunRouter, handler)
// This gives you the full uptrace stack: bunrouter + Bun ORM
// http.ListenAndServe(":8080", bunRouter.GetBunRouter())
// http.ListenAndServe(":8080", bunRouter)
}
// ExampleBunRouterWithGroup shows how to use SetupBunRouterRoutes with a bunrouter.Group
func ExampleBunRouterWithGroup(bunDB *bun.DB) {
// Create handler with Bun adapter
handler := NewHandlerWithBun(bunDB)
// Create bunrouter
bunRouter := bunrouter.New()
// Create a route group with a prefix
apiGroup := bunRouter.NewGroup("/api")
// Setup ResolveSpec routes on the group - routes will be under /api
SetupBunRouterRoutes(apiGroup, handler)
// Start server
// http.ListenAndServe(":8080", bunRouter)
}

View File

@@ -270,9 +270,14 @@ func ExampleWithBun(bunDB *bun.DB) {
SetupMuxRoutes(muxRouter, handler, nil)
}
// BunRouterHandler is an interface that both bunrouter.Router and bunrouter.Group implement
type BunRouterHandler interface {
Handle(method, path string, handler bunrouter.HandlerFunc)
}
// SetupBunRouterRoutes sets up bunrouter routes for the RestHeadSpec API
func SetupBunRouterRoutes(bunRouter *router.StandardBunRouterAdapter, handler *Handler) {
r := bunRouter.GetBunRouter()
// Accepts bunrouter.Router or bunrouter.Group
func SetupBunRouterRoutes(r BunRouterHandler, handler *Handler) {
// CORS config
corsConfig := common.DefaultCORSConfig()
@@ -450,17 +455,34 @@ func ExampleBunRouterWithBunDB(bunDB *bun.DB) {
// Create handler
handler := NewHandlerWithBun(bunDB)
// Create BunRouter adapter
routerAdapter := NewStandardBunRouter()
// Create bunrouter
bunRouter := bunrouter.New()
// Setup routes
SetupBunRouterRoutes(routerAdapter, handler)
// Get the underlying router for server setup
r := routerAdapter.GetBunRouter()
SetupBunRouterRoutes(bunRouter, handler)
// Start server
if err := http.ListenAndServe(":8080", r); err != nil {
if err := http.ListenAndServe(":8080", bunRouter); err != nil {
logger.Error("Server failed to start: %v", err)
}
}
// ExampleBunRouterWithGroup shows how to use SetupBunRouterRoutes with a bunrouter.Group
func ExampleBunRouterWithGroup(bunDB *bun.DB) {
// Create handler with Bun adapter
handler := NewHandlerWithBun(bunDB)
// Create bunrouter
bunRouter := bunrouter.New()
// Create a route group with a prefix
apiGroup := bunRouter.NewGroup("/api")
// Setup RestHeadSpec routes on the group - routes will be under /api
SetupBunRouterRoutes(apiGroup, handler)
// Start server
if err := http.ListenAndServe(":8080", bunRouter); err != nil {
logger.Error("Server failed to start: %v", err)
}
}

View File

@@ -3,6 +3,7 @@ package staticweb
import (
"io/fs"
"net/http"
"reflect"
)
// FileSystemProvider abstracts the source of files (local, zip, embedded, future: http, s3)
@@ -34,6 +35,32 @@ type ReloadableProvider interface {
Reload() error
}
// PrefixStrippingProvider is an optional interface that providers can implement
// to support stripping path prefixes from requested paths.
// This is useful when files are stored in a subdirectory but should be accessible
// at the root level (e.g., files at "/dist/assets" accessible via "/assets").
type PrefixStrippingProvider interface {
// WithStripPrefix sets the prefix to strip from requested paths.
// For example, WithStripPrefix("/dist") will make files at "/dist/assets"
// accessible via "/assets".
WithStripPrefix(prefix string)
// StripPrefix returns the configured strip prefix.
StripPrefix() string
}
// WithStripPrefix is a helper function that sets the strip prefix on a provider
// if it implements PrefixStrippingProvider. Returns the provider for method chaining.
func WithStripPrefix(provider FileSystemProvider, prefix string) FileSystemProvider {
if provider == nil || reflect.ValueOf(provider).IsNil() {
return provider
}
if p, ok := provider.(PrefixStrippingProvider); ok && p != nil {
p.WithStripPrefix(prefix)
}
return provider
}
// CachePolicy defines how files should be cached by browsers and proxies.
// Implementations must be safe for concurrent use.
type CachePolicy interface {

View File

@@ -7,6 +7,8 @@ import (
"fmt"
"io"
"io/fs"
"path"
"strings"
"sync"
"github.com/bitechdev/ResolveSpec/pkg/server/zipfs"
@@ -15,16 +17,18 @@ import (
// EmbedFSProvider serves files from an embedded filesystem.
// It supports both direct embedded directories and embedded zip files.
type EmbedFSProvider struct {
embedFS *embed.FS
zipFile string // Optional: path within embedded FS to zip file
zipReader *zip.Reader
fs fs.FS
mu sync.RWMutex
embedFS *embed.FS
zipFile string // Optional: path within embedded FS to zip file
stripPrefix string // Optional: prefix to strip from requested paths (e.g., "/dist")
zipReader *zip.Reader
fs fs.FS
mu sync.RWMutex
}
// NewEmbedFSProvider creates a new EmbedFSProvider.
// If zipFile is empty, the embedded FS is used directly.
// If zipFile is specified, it's treated as a path to a zip file within the embedded FS.
// Use WithStripPrefix to configure path prefix stripping.
func NewEmbedFSProvider(embedFS fs.FS, zipFile string) (*EmbedFSProvider, error) {
if embedFS == nil {
return nil, fmt.Errorf("embedded filesystem cannot be nil")
@@ -81,6 +85,9 @@ func NewEmbedFSProvider(embedFS fs.FS, zipFile string) (*EmbedFSProvider, error)
}
// Open opens the named file from the embedded filesystem.
// If a strip prefix is configured, it prepends the prefix to the requested path.
// For example, with stripPrefix="/dist", requesting "/assets/style.css" will
// open "/dist/assets/style.css" from the embedded filesystem.
func (p *EmbedFSProvider) Open(name string) (fs.File, error) {
p.mu.RLock()
defer p.mu.RUnlock()
@@ -89,7 +96,21 @@ func (p *EmbedFSProvider) Open(name string) (fs.File, error) {
return nil, fmt.Errorf("embedded filesystem is closed")
}
return p.fs.Open(name)
// Apply prefix stripping by prepending the prefix to the requested path
actualPath := name
if p.stripPrefix != "" {
// Clean the paths to handle leading/trailing slashes
prefix := strings.Trim(p.stripPrefix, "/")
cleanName := strings.TrimPrefix(name, "/")
if prefix != "" {
actualPath = path.Join(prefix, cleanName)
} else {
actualPath = cleanName
}
}
return p.fs.Open(actualPath)
}
// Close releases any resources held by the provider.
@@ -117,3 +138,19 @@ func (p *EmbedFSProvider) Type() string {
func (p *EmbedFSProvider) ZipFile() string {
return p.zipFile
}
// WithStripPrefix sets the prefix to strip from requested paths.
// For example, WithStripPrefix("/dist") will make files at "/dist/assets"
// accessible via "/assets".
func (p *EmbedFSProvider) WithStripPrefix(prefix string) {
p.mu.Lock()
defer p.mu.Unlock()
p.stripPrefix = prefix
}
// StripPrefix returns the configured strip prefix.
func (p *EmbedFSProvider) StripPrefix() string {
p.mu.RLock()
defer p.mu.RUnlock()
return p.stripPrefix
}

View File

@@ -4,13 +4,18 @@ import (
"fmt"
"io/fs"
"os"
"path"
"path/filepath"
"strings"
"sync"
)
// LocalFSProvider serves files from a local directory.
type LocalFSProvider struct {
path string
fs fs.FS
path string
stripPrefix string
fs fs.FS
mu sync.RWMutex
}
// NewLocalFSProvider creates a new LocalFSProvider for the given directory path.
@@ -39,8 +44,28 @@ func NewLocalFSProvider(path string) (*LocalFSProvider, error) {
}
// Open opens the named file from the local directory.
// If a strip prefix is configured, it prepends the prefix to the requested path.
// For example, with stripPrefix="/dist", requesting "/assets/style.css" will
// open "/dist/assets/style.css" from the local filesystem.
func (p *LocalFSProvider) Open(name string) (fs.File, error) {
return p.fs.Open(name)
p.mu.RLock()
defer p.mu.RUnlock()
// Apply prefix stripping by prepending the prefix to the requested path
actualPath := name
if p.stripPrefix != "" {
// Clean the paths to handle leading/trailing slashes
prefix := strings.Trim(p.stripPrefix, "/")
cleanName := strings.TrimPrefix(name, "/")
if prefix != "" {
actualPath = path.Join(prefix, cleanName)
} else {
actualPath = cleanName
}
}
return p.fs.Open(actualPath)
}
// Close releases any resources held by the provider.
@@ -63,6 +88,9 @@ func (p *LocalFSProvider) Path() string {
// For local directories, os.DirFS automatically picks up changes,
// so this recreates the DirFS to ensure a fresh view.
func (p *LocalFSProvider) Reload() error {
p.mu.Lock()
defer p.mu.Unlock()
// Verify the directory still exists
info, err := os.Stat(p.path)
if err != nil {
@@ -78,3 +106,19 @@ func (p *LocalFSProvider) Reload() error {
return nil
}
// WithStripPrefix sets the prefix to strip from requested paths.
// For example, WithStripPrefix("/dist") will make files at "/dist/assets"
// accessible via "/assets".
func (p *LocalFSProvider) WithStripPrefix(prefix string) {
p.mu.Lock()
defer p.mu.Unlock()
p.stripPrefix = prefix
}
// StripPrefix returns the configured strip prefix.
func (p *LocalFSProvider) StripPrefix() string {
p.mu.RLock()
defer p.mu.RUnlock()
return p.stripPrefix
}

View File

@@ -4,7 +4,9 @@ import (
"archive/zip"
"fmt"
"io/fs"
"path"
"path/filepath"
"strings"
"sync"
"github.com/bitechdev/ResolveSpec/pkg/server/zipfs"
@@ -12,10 +14,11 @@ import (
// ZipFSProvider serves files from a zip file.
type ZipFSProvider struct {
zipPath string
zipReader *zip.ReadCloser
zipFS *zipfs.ZipFS
mu sync.RWMutex
zipPath string
stripPrefix string
zipReader *zip.ReadCloser
zipFS *zipfs.ZipFS
mu sync.RWMutex
}
// NewZipFSProvider creates a new ZipFSProvider for the given zip file path.
@@ -40,6 +43,9 @@ func NewZipFSProvider(zipPath string) (*ZipFSProvider, error) {
}
// Open opens the named file from the zip archive.
// If a strip prefix is configured, it prepends the prefix to the requested path.
// For example, with stripPrefix="/dist", requesting "/assets/style.css" will
// open "/dist/assets/style.css" from the zip filesystem.
func (p *ZipFSProvider) Open(name string) (fs.File, error) {
p.mu.RLock()
defer p.mu.RUnlock()
@@ -48,7 +54,21 @@ func (p *ZipFSProvider) Open(name string) (fs.File, error) {
return nil, fmt.Errorf("zip filesystem is closed")
}
return p.zipFS.Open(name)
// Apply prefix stripping by prepending the prefix to the requested path
actualPath := name
if p.stripPrefix != "" {
// Clean the paths to handle leading/trailing slashes
prefix := strings.Trim(p.stripPrefix, "/")
cleanName := strings.TrimPrefix(name, "/")
if prefix != "" {
actualPath = path.Join(prefix, cleanName)
} else {
actualPath = cleanName
}
}
return p.zipFS.Open(actualPath)
}
// Close releases resources held by the zip reader.
@@ -100,3 +120,19 @@ func (p *ZipFSProvider) Reload() error {
return nil
}
// WithStripPrefix sets the prefix to strip from requested paths.
// For example, WithStripPrefix("/dist") will make files at "/dist/assets"
// accessible via "/assets".
func (p *ZipFSProvider) WithStripPrefix(prefix string) {
p.mu.Lock()
defer p.mu.Unlock()
p.stripPrefix = prefix
}
// StripPrefix returns the configured strip prefix.
func (p *ZipFSProvider) StripPrefix() string {
p.mu.RLock()
defer p.mu.RUnlock()
return p.stripPrefix
}